# GroupPickupServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.SystemPlatformEnum;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.rateshop.cons.rateshop.BookingStatusEnum;
    import cloud.wconnect.rateshop.cons.rateshop.GroupPickupDataSourceEnum;
    import cloud.wconnect.rateshop.entity.rateshop.GroupPickup;
    import cloud.wconnect.rateshop.mapper.rateshop.GroupPickupMapper;
    import cloud.wconnect.rateshop.pojo.bo.rateshop.GroupPickupBO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.internal.InternalGroupPickupDTO;
    import cloud.wconnect.rateshop.pojo.query.rateshop.GroupPickupQuery;
    import cloud.wconnect.rateshop.pojo.vo.rateshop.GroupPickupVO;
    import cloud.wconnect.rateshop.service.rateshop.IGroupPickupDataSourceService;
    import cloud.wconnect.rateshop.service.rateshop.IGroupPickupService;
    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 com.google.common.collect.Lists;
    import org.apache.commons.collections4.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.math.RoundingMode;
    import java.time.LocalDate;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Objects;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author zc
     * @since 2024-03-23
     */
    @Service
    @DS("rate_shop")
    public class GroupPickupServiceImpl extends ServiceImpl<GroupPickupMapper, GroupPickup> implements IGroupPickupService {

        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private IGroupPickupDataSourceService groupPickupDataSourceService;

        /**
         * 保存 pms group pickup 报告数据
         *
         * @param propertyDTO       资产DTO
         * @param operatorId        操作人 id
         * @param groupPickupBOList 报告数据
         * @param startDate         数据日期，开始时间
         * @param endDate           数据日期，结束时间
         * @param source            来源
         * @author zc
         * @date 2024/3/25
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void savePmsGroupPickupReportData(PropertyDTO propertyDTO, int operatorId, List<GroupPickupBO> groupPickupBOList,
                                                 long startDate, long endDate, String source) {
            ArrayList<Integer> statusList = new ArrayList<>();
            statusList.add(BookingStatusEnum.DEFINITE.getCode());
            statusList.add(BookingStatusEnum.TENTATIVE.getCode());

            // 导入 Shiji、Other 类型的数据时，同步删除：PROSPECT、CANCELLED
            if (Lists.newArrayList(SystemPlatformEnum.SHI_JI.getDesc(),
                    SystemPlatformEnum.OTHER.getDesc()).contains(source)) {
                statusList.add(BookingStatusEnum.PROSPECT.getCode());
                statusList.add(BookingStatusEnum.CANCELLED.getCode());
            }

            // 删除目标日期范围数据，PMS 报告中只包含：1:Definite 2:Tentative 预定状态的数据
            remove(new LambdaQueryWrapper<GroupPickup>()
                    .between(GroupPickup::getTargetDate, startDate, endDate)
                    .eq(GroupPickup::getPropertyId, propertyDTO.getId())
                    .in(GroupPickup::getBookingStatus, statusList));

            if (CollectionUtils.isEmpty(groupPickupBOList)) return;

            long nowTimestamp = DateTimeUtils.nowTimestamp();
            List<GroupPickup> groupPickups = beanMapper.mapList(groupPickupBOList,
                    GroupPickup.class, (bo, entity) -> {
                        entity.setPropertyId(propertyDTO.getId());
                        entity.setTargetDate(DateTimeUtils.dateStrToEpochSecond(bo.getDate(),
                                BaseConstant.DATE_FORMAT_YYYY_MM_DD, propertyDTO.getTimezone()));
                        entity.setUpdatedBy(operatorId);
                        entity.setUpdatedTime(nowTimestamp);
                    });

            // 保存数据
            saveBatch(groupPickups);

            // 记录 group pickup 更新时间
            groupPickupDataSourceService.saveBatch(propertyDTO.getId(), GroupPickupDataSourceEnum.PMS.getCode(),
                    groupPickupBOList.stream()
                            .map(item -> Integer.parseInt(DateTimeUtils.localDateToStr(DateTimeUtils.strToLocalDate(item.getDate(),
                                    BaseConstant.DATE_FORMAT_YYYY_MM_DD), BaseConstant.DATE_FORMAT_YYYYMMDD)))
                            .distinct().collect(Collectors.toList()),
                    statusList);
        }

        /**
         * 保存采集的 Group Pickup 数据 from Salesforce
         *
         * @param propertyDTO    资产DTO
         * @param groupPickupDTO 数据DTO
         * @author zc
         * @date 2024/3/25
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void saveCollectGroupPickup(PropertyDTO propertyDTO, InternalGroupPickupDTO groupPickupDTO) {
            RoundingMode roundingMode = InternationalizationUtils.getRoundingMode(propertyDTO
                    .getInternationalization().getNumber().getCalculationRule());

            List<Integer> bookingStatusList;
            if (SystemPlatformEnum.SHI_JI.getDesc().equals(propertyDTO.getPmsType())) {
                // 使用Shiji PMS系统的资产，从Salesforce系统采集所有状态的Group pickup数据
                bookingStatusList = Arrays.stream(BookingStatusEnum.values()).map(BookingStatusEnum::getCode).toList();
            } else {
                // 使用Opera PMS系统的资产，从Salesforce系统采集3:Prospect 4:Cancelled状态的Group pickup数据
                bookingStatusList = List.of(BookingStatusEnum.PROSPECT.getCode(), BookingStatusEnum.CANCELLED.getCode());
            }

            // 删除目标日期范围数据
            long startTimestamp = DateTimeUtils.dateStrToEpochSecond(groupPickupDTO.getStartDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD, propertyDTO.getTimezone());
            long endTimestamp = DateTimeUtils.dateStrToEpochSecond(groupPickupDTO.getEndDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD, propertyDTO.getTimezone());
            remove(new LambdaQueryWrapper<GroupPickup>()
                    .between(GroupPickup::getTargetDate, startTimestamp, endTimestamp)
                    .eq(GroupPickup::getPropertyId, propertyDTO.getId())
                    .in(GroupPickup::getBookingStatus, bookingStatusList));

            long nowTimestamp = DateTimeUtils.nowTimestamp();
            List<GroupPickup> groupPickups = beanMapper.mapList(groupPickupDTO.getDataList(),
                    GroupPickup.class, (dto, entity) -> {
                        entity.setPropertyId(propertyDTO.getId());
                        entity.setTargetDate(DateTimeUtils.dateStrToEpochSecond(dto.getTheDate().toString(),
                                BaseConstant.DATE_FORMAT_YYYYMMDD, propertyDTO.getTimezone()));
                        entity.setRateBlocked(dto.getRateBlocked().setScale(BaseConstant.DATA_PRECISION, roundingMode));
                        entity.setRatePickup(dto.getRatePickup().setScale(BaseConstant.DATA_PRECISION, roundingMode));
                        entity.setUpdatedBy(BaseConstant.ZERO);
                        entity.setUpdatedTime(nowTimestamp);
                    });

            // 保存数据
            saveBatch(groupPickups);

            LocalDate startLocalDate = DateTimeUtils.strToLocalDate(groupPickupDTO.getStartDate().toString(), BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate endLocalDate = DateTimeUtils.strToLocalDate(groupPickupDTO.getEndDate().toString(), BaseConstant.DATE_FORMAT_YYYYMMDD);
            ArrayList<Integer> targetDateList = Lists.newArrayList();
            for (LocalDate localDate = startLocalDate; !localDate.isAfter(endLocalDate); localDate = localDate.plusDays(1)) {
                targetDateList.add(Integer.valueOf(DateTimeUtils.localDateToStr(localDate, BaseConstant.DATE_FORMAT_YYYYMMDD)));
            }
            // 保存 Group Pickup 更新时间
            groupPickupDataSourceService.saveBatch(propertyDTO.getId(), GroupPickupDataSourceEnum.BUSINESS_PLATFORM.getCode(),
                    targetDateList, bookingStatusList);
        }

        /**
         * 查询指定日期区间的 Group Pickup 数据
         *
         * @param propertyId 资产 id
         * @param startDate  开始日期
         * @param endDate    结束日期
         * @return Group Pickup 数据
         * @author yyt
         * @date 2025/6/11
         **/
        @Override
        public List<GroupPickup> list(Integer propertyId, long startDate, long endDate) {
            return list(new QueryWrapper<GroupPickup>().lambda()
                    .eq(GroupPickup::getPropertyId, propertyId)
                    .between(GroupPickup::getTargetDate, startDate, endDate));
        }

        /**
         * 分页查询 Group Pickup 数据
         *
         * @param propertyDTO 资产DTO
         * @param query       查询条件
         * @return Group Pickup 数据
         * @author lichen
         * @date 2025/12/30
         **/
        @Override
        public ListPagedDTO<GroupPickupVO> pageList(PropertyDTO propertyDTO, GroupPickupQuery query) {
            LambdaQueryWrapper<GroupPickup> queryWrapper = new QueryWrapper<GroupPickup>().lambda()
                    .eq(GroupPickup::getPropertyId, propertyDTO.getId())
                    .eq(GroupPickup::getTargetDate, DateTimeUtils.dateStrToEpochSecond(query.getTheDate(),
                            BaseConstant.DATE_FORMAT_YYYY_MM_DD, propertyDTO.getTimezone()))
                    .eq(GroupPickup::getBookingStatus, query.getBookingStatus())
                    .orderByDesc(GroupPickup::getId);

            long total;
            List<GroupPickup> records;
            if (Objects.nonNull(query.getPage()) && Objects.nonNull(query.getSize())) {
                Page<GroupPickup> pageResult = page(new Page<>(query.getPage(),
                        query.getSize()), queryWrapper);
                records = pageResult.getRecords();
                total = pageResult.getTotal();
            } else {
                records = list(queryWrapper);
                total = records.size();
            }
            if (org.apache.commons.collections.CollectionUtils.isEmpty(records)) {
                return new ListPagedDTO<>();
            }

            return new ListPagedDTO<>(total, beanMapper.mapList(records, GroupPickupVO.class));
        }
    }