# TaCompareOtaContractPriceConfigServiceImpl.java

    package cloud.wconnect.finance.service.ta.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.UpdateLogUtil;
    import cloud.wconnect.finance.cons.ta.TaCompareConfigCons;
    import cloud.wconnect.finance.entity.ta.TaCompareOtaContractPriceConfig;
    import cloud.wconnect.finance.mapper.ta.TaCompareOtaContractPriceConfigMapper;
    import cloud.wconnect.finance.pojo.dto.ta.compare.TaCompareListDTO;
    import cloud.wconnect.finance.pojo.dto.ta.compare.TaCompareOtaContractPriceConfigDTO;
    import cloud.wconnect.finance.pojo.query.ta.TaCompareListQuery;
    import cloud.wconnect.finance.service.ta.ITaCompareOtaContractPriceConfigService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.stereotype.Service;

    import jakarta.annotation.Resource;

    import java.text.MessageFormat;
    import java.util.List;
    import java.util.Objects;

    /**
     * <p>
     * TA Credit Card 报告比对OTA合约价配置 服务实现类
     * </p>
     *
     * @author zc
     * @since 2023-07-07
     */
    @Service
    @DS("finance")
    public class TaCompareOtaContractPriceConfigServiceImpl extends ServiceImpl<TaCompareOtaContractPriceConfigMapper, TaCompareOtaContractPriceConfig> implements ITaCompareOtaContractPriceConfigService {
        @Resource
        private UpdateLogUtil updateLogUtil;
        @Resource
        private BeanMapper beanMapper;

        /**
         * 获取最新版本的 OTA 合约价配置数据
         *
         * @param tenantId   租户 id
         * @param propertyId 资产 id
         * @return TaCompareOtaContractPriceConfigDTO
         * @author zc
         * @date 2023/7/7
         */
        @Override
        public TaCompareOtaContractPriceConfigDTO getLatest(int tenantId, int propertyId) {
            TaCompareOtaContractPriceConfig contractPriceConfig = getOne(new QueryWrapper<TaCompareOtaContractPriceConfig>().lambda()
                    .eq(TaCompareOtaContractPriceConfig::getTenantId, tenantId)
                    .eq(TaCompareOtaContractPriceConfig::getPropertyId, propertyId)
                    .orderByDesc(TaCompareOtaContractPriceConfig::getStartingDate)
                    .last("limit 1"));
            if (Objects.isNull(contractPriceConfig)) {
                return null;
            }

            return beanMapper.map(contractPriceConfig, TaCompareOtaContractPriceConfigDTO.class);
        }

        /**
         * 获取当前应用的 OTA 合约价配置数据
         *
         * @param tenantId   租户 id
         * @param propertyId 资产 id
         * @param targetDate 目标日期
         * @return TaCompareOtaContractPriceConfigDTO
         * @author zc
         * @date 2023/7/7
         */
        @Override
        public TaCompareOtaContractPriceConfigDTO getCurrent(int tenantId, int propertyId, long targetDate) {
            TaCompareOtaContractPriceConfig contractPriceConfig = getOne(new QueryWrapper<TaCompareOtaContractPriceConfig>().lambda()
                    .eq(TaCompareOtaContractPriceConfig::getTenantId, tenantId)
                    .eq(TaCompareOtaContractPriceConfig::getPropertyId, propertyId)
                    .le(TaCompareOtaContractPriceConfig::getStartingDate, targetDate)
                    .orderByDesc(TaCompareOtaContractPriceConfig::getStartingDate)
                    .last("limit 1"));
            if (Objects.isNull(contractPriceConfig)) {
                return null;
            }

            return beanMapper.map(contractPriceConfig, TaCompareOtaContractPriceConfigDTO.class);
        }

        /**
         * 获取有效的 OTA 合约价配置数据
         *
         * @param tenantId   租户 id
         * @param propertyId 资产 id
         * @param targetDate 目标日期
         * @param isGreater  0: 获取大于目标日期的数据；1: 获取小于目标日期的数据；2: 获取等于目标日期的数据
         * @return TaCompareOtaContractPriceConfigDTO
         * @author zc
         * @date 2023/7/7
         */
        @Override
        public TaCompareOtaContractPriceConfigDTO getEffective(int tenantId, int propertyId, long targetDate, Integer isGreater) {
            LambdaQueryWrapper<TaCompareOtaContractPriceConfig> queryWrapper = new QueryWrapper<TaCompareOtaContractPriceConfig>().lambda()
                    .eq(TaCompareOtaContractPriceConfig::getTenantId, tenantId)
                    .eq(TaCompareOtaContractPriceConfig::getPropertyId, propertyId);
            if (TaCompareConfigCons.GREATER_THAN == isGreater) {
                queryWrapper.gt(TaCompareOtaContractPriceConfig::getStartingDate, targetDate)
                        .orderByAsc(TaCompareOtaContractPriceConfig::getStartingDate);
            } else if (TaCompareConfigCons.LESS_THAN == isGreater) {
                queryWrapper.lt(TaCompareOtaContractPriceConfig::getStartingDate, targetDate)
                        .orderByDesc(TaCompareOtaContractPriceConfig::getStartingDate);
            } else if (TaCompareConfigCons.EQUAL_TO == isGreater) {
                queryWrapper.eq(TaCompareOtaContractPriceConfig::getStartingDate, targetDate);
            }

            TaCompareOtaContractPriceConfig roomNoConfig = getOne(queryWrapper.last("limit 1"));
            if (Objects.isNull(roomNoConfig)) {
                return null;
            }

            return beanMapper.map(roomNoConfig, TaCompareOtaContractPriceConfigDTO.class);
        }

        /**
         * 新增 OTA 合约价配置数据
         *
         * @param tenantId               租户 id
         * @param propertyId             资产 id
         * @param contractPriceConfigDTO OTA 合约价配置数据
         * @param loginUserId            登录用户id
         * @return long
         * @author zc
         * @date 2023/7/8
         */
        @Override
        public long insert(int tenantId, int propertyId, TaCompareOtaContractPriceConfigDTO contractPriceConfigDTO, int loginUserId) {
            // 校验指定生效日期的 OTA 合约价配置数据是否已存在
            checkExistByStartingDate(tenantId, propertyId, contractPriceConfigDTO);

            TaCompareOtaContractPriceConfig contractPriceConfig = beanMapper.map(contractPriceConfigDTO,
                    TaCompareOtaContractPriceConfig.class);

            contractPriceConfig.setTenantId(tenantId);
            contractPriceConfig.setPropertyId(propertyId);
            contractPriceConfig.setUpdateLog(updateLogUtil.get(loginUserId));
            save(contractPriceConfig);

            return contractPriceConfig.getId();
        }

        /**
         * 编辑 OTA 合约价配置数据
         *
         * @param tenantId                  租户 id
         * @param propertyId                资产 id
         * @param originContractPriceConfig 原 OTA 合约价配置数据
         * @param contractPriceConfigDTO    OTA 合约价配置数据
         * @param loginUserId               登录用户id
         * @author zc
         * @date 2023/7/8
         */
        @Override
        public void update(int tenantId, int propertyId,
                           TaCompareOtaContractPriceConfig originContractPriceConfig,
                           TaCompareOtaContractPriceConfigDTO contractPriceConfigDTO,
                           int loginUserId) {
            // 校验指定生效日期的 OTA 合约价配置数据是否已存在
            checkExistByStartingDate(tenantId, propertyId, contractPriceConfigDTO);

            updateById(TaCompareOtaContractPriceConfig.builder()
                    .id(originContractPriceConfig.getId())
                    .startingDate(contractPriceConfigDTO.getStartingDate())
                    .contractPrice(contractPriceConfigDTO.getContractPrice())
                    .updateLog(updateLogUtil.append(originContractPriceConfig.getUpdateLog(), loginUserId))
                    .build());
        }

        /**
         * 校验 OTA 合约价配置数据是否存在
         *
         * @param id OTA 合约价配置数据 id
         * @return TaCompareOtaContractPriceConfig
         * @author zc
         * @date 2023/7/8
         */
        @Override
        public TaCompareOtaContractPriceConfig checkExist(long id) {
            TaCompareOtaContractPriceConfig contractPriceConfig = getById(id);
            if (Objects.isNull(contractPriceConfig)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The OTA contract price config is not found; contractPriceConfigId: " + id);
            }
            return contractPriceConfig;
        }

        /**
         * 校验数据归属
         *
         * @param tenantId            租户 id
         * @param propertyId          资产 id
         * @param contractPriceConfig OTA 合约价配置数据
         * @author zc
         * @date 2023/7/8
         */
        @Override
        public void checkBelong(int tenantId, int propertyId, TaCompareOtaContractPriceConfig contractPriceConfig) {
            if (!contractPriceConfig.getTenantId().equals(tenantId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The OTA contract price config does not belong to this tenant; tenantId:{0}; contractPriceConfigId:{1}",
                                tenantId, contractPriceConfig.getId()));
            }

            if (!contractPriceConfig.getPropertyId().equals(propertyId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The OTA contract price config does not belong to this property; propertyId:{0}; contractPriceConfigId:{1}",
                                propertyId, contractPriceConfig.getId()));
            }
        }

        /**
         * 获取 OTA 合约价配置数据集合
         *
         * @param tenantId           租户 id
         * @param propertyId         资产 id
         * @param taCompareListQuery 查询条件
         * @return TaCompareListDTO 集合
         * @author zc
         * @date 2023/7/7
         */
        @Override
        public ListPagedDTO<TaCompareListDTO> list(int tenantId, int propertyId, TaCompareListQuery taCompareListQuery) {
            LambdaQueryWrapper<TaCompareOtaContractPriceConfig> queryWrapper = new QueryWrapper<TaCompareOtaContractPriceConfig>().lambda()
                    .eq(TaCompareOtaContractPriceConfig::getTenantId, tenantId)
                    .eq(TaCompareOtaContractPriceConfig::getPropertyId, propertyId)
                    .orderByDesc(TaCompareOtaContractPriceConfig::getStartingDate);
            Page<TaCompareOtaContractPriceConfig> paged = page(new Page<>(taCompareListQuery.getPage(), taCompareListQuery.getSize()), queryWrapper);
            if (CollectionUtils.isEmpty(paged.getRecords())) {
                return new ListPagedDTO<>();
            }

            return new ListPagedDTO<>(paged.getTotal(), beanMapper.mapList(paged.getRecords(), TaCompareListDTO.class));
        }

        /**
         * 过滤配置了 OTA 合约价数据的资产集合
         *
         * @param propertyList 资产集合
         * @return 资产集合
         * @author zc
         * @date 2024/2/29
         */
        @Override
        public List<PropertyDTO> filterPriceConfigProperty(List<PropertyDTO> propertyList) {
            if (CollectionUtils.isEmpty(propertyList)) {
                return propertyList;
            }
            List<Integer> propertyIds = propertyList.stream().map(PropertyDTO::getId).toList();
            List<Integer> priceConfigPropertyIds = list(new QueryWrapper<TaCompareOtaContractPriceConfig>().lambda()
                    .in(TaCompareOtaContractPriceConfig::getPropertyId, propertyIds)
                    .select(TaCompareOtaContractPriceConfig::getPropertyId)).stream()
                    .map(TaCompareOtaContractPriceConfig::getPropertyId).toList();

            return propertyList.stream().filter(property ->
                    priceConfigPropertyIds.contains(property.getId())).toList();
        }

        /**
         * 校验指定生效日期的 OTA 合约价配置数据是否已存在
         *
         * @param tenantId               租户 id
         * @param propertyId             资产 id
         * @param contractPriceConfigDTO OTA 合约价配置数据
         * @author zc
         * @date 2023/7/7
         */
        private void checkExistByStartingDate(int tenantId, int propertyId, TaCompareOtaContractPriceConfigDTO contractPriceConfigDTO) {
            long count = count(new QueryWrapper<TaCompareOtaContractPriceConfig>().lambda()
                    .eq(TaCompareOtaContractPriceConfig::getTenantId, tenantId)
                    .eq(TaCompareOtaContractPriceConfig::getPropertyId, propertyId)
                    .eq(TaCompareOtaContractPriceConfig::getStartingDate, contractPriceConfigDTO.getStartingDate())
                    .ne(Objects.nonNull(contractPriceConfigDTO.getId()), TaCompareOtaContractPriceConfig::getId, contractPriceConfigDTO.getId()));
            if (count > 0) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_EXISTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The OTA contract price config startingDate has existed in current property; startingDate: " + contractPriceConfigDTO.getStartingDate());
            }
        }
    }