# PastReservationController.java

    package cloud.wconnect.frontoffice.controller.pastreservation;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.*;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.bo.SymbolBO;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.group.Edition;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.frontoffice.cons.pastreservation.PastReservationErrorFiledCons;
    import cloud.wconnect.frontoffice.cons.pastreservation.PastReservationStatusEnum;
    import cloud.wconnect.frontoffice.entity.pastreservation.PastReservation;
    import cloud.wconnect.frontoffice.entity.pastreservation.PastReservationComment;
    import cloud.wconnect.frontoffice.entity.pastreservation.PastReservationImportLog;
    import cloud.wconnect.frontoffice.entity.pastreservation.PastReservationOpGuestinHouse;
    import cloud.wconnect.frontoffice.pojo.dto.clc.ImportGuestInHouseLogDTO;
    import cloud.wconnect.frontoffice.pojo.dto.pastreservation.*;
    import cloud.wconnect.frontoffice.pojo.group.Addition;
    import cloud.wconnect.frontoffice.pojo.query.clc.GuestInHouseImportLogQuery;
    import cloud.wconnect.frontoffice.pojo.query.pastreservation.CheckGuestExistQuery;
    import cloud.wconnect.frontoffice.pojo.query.pastreservation.PastReservationQuery;
    import cloud.wconnect.frontoffice.service.pastreservation.IPastReservationCommentService;
    import cloud.wconnect.frontoffice.service.pastreservation.IPastReservationImportLogService;
    import cloud.wconnect.frontoffice.service.pastreservation.IPastReservationOpGuestinHouseService;
    import cloud.wconnect.frontoffice.service.pastreservation.IPastReservationService;
    import cloud.wconnect.frontoffice.service.pastreservation.report.manualimport.IPastReservationReportParse;
    import com.google.common.collect.ImmutableMap;
    import com.google.common.collect.Lists;
    import jakarta.annotation.Resource;
    import jakarta.validation.Valid;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;

    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Map;
    import java.util.Objects;

    /**
     * <p>
     * 连续入住人员信息表 前端控制器
     * </p>
     *
     * @author yyt
     * @since 2024-10-01
     */
    @RestController
    @RequestMapping("/past-reservations")
    public class PastReservationController {

        @Resource
        private IPastReservationService pastReservationService;
        @Resource
        private IPastReservationCommentService pastReservationCommentService;
        @Resource
        private IPastReservationImportLogService pastReservationImportLogService;
        @Resource
        private IPastReservationOpGuestinHouseService pastReservationOpGuestinHouseService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private ApplicationContext applicationContext;
        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 1253 - 统计连续入住
         *
         * @param property 资产标识
         * @return 统计连续入住
         * @author yyt
         * @date 2024/10/1
         **/
        @ApiId(1253)
        @GetMapping("/statistics")
        public PastReservationStatisticsDTO statistics(String property) {
            Integer propertyId = sessionContext.getPropertyId(property);
            return pastReservationService.statistics(propertyId);
        }

        /**
         * 1254 - 连续入住列表
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return 连续入住列表
         * @author yyt
         * @date 2024/10/2
         **/
        @ApiId(1254)
        @GetMapping
        public ListPagedDTO<PastReservationDTO> list(String property, @Valid PastReservationQuery query) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(sessionContext.getPropertyId(property));
            return pastReservationService.listPage(propertyDTO, query);
        }

        /**
         * 1298 - 连续入住列表 客人姓名验重
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return true:已存在 false:不存在
         * @author yyt
         * @date 2024/10/31
         **/
        @ApiId(1298)
        @GetMapping("/name-check")
        public Map checkName(String property, CheckGuestExistQuery query) {
            Integer propertyId = sessionContext.getPropertyId(property);

            return ImmutableMap.of("exist", pastReservationService.checkRepeat(propertyId, query.getFirstName(), query.getLastName(), query.getId()));
        }

        /**
         * 1255 - 新增连续入住人员信息
         *
         * @param property 资产标识
         * @param dto      修改的连续入住人员信息
         * @return {}
         * @author yyt
         * @date 2024/10/2
         **/
        @ApiId(1255)
        @PostMapping
        public Map save(String property, @Validated(Addition.class) @RequestBody SaveCheckInRecordDTO dto) {
            Integer propertyId = sessionContext.getPropertyId(property);
            int userId = sessionContext.getLoginUserId();

            // 校验名称重复
            if (pastReservationService.checkRepeat(propertyId, dto.getFirstName(), dto.getLastName(), null)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_EXISTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the pastReservation is existed");
            }

            PastReservation pastReservation = pastReservationService.save(propertyId, dto, userId);

            return ImmutableMap.of("showGuest", Objects.nonNull(pastReservation));
        }

        /**
         * 1290 - 查看详情
         *
         * @param id 连续入住数据 id
         * @param property 资产标识
         * @return 连续入住详情
         * @author yyt
         * @date 2024/10/15
         **/
        @ApiId(1290)
        @GetMapping("/{id:\\d+}")
        public PastReservationDetailDTO get(@PathVariable long id, String property) {
            PastReservation pastReservation = pastReservationService.checkExist(id);
            checkBelong(pastReservation, sessionContext.getPropertyId(property));
            checkEffective(pastReservation);

            return pastReservationService.getPastReservationDetailDTO(pastReservation);
        }

        /**
         * 1291 - 修改客户姓名
         *
         * @param id                 连续入住数据 id
         * @param property           资产标识
         * @param updateGuestNameDTO 客户姓名
         * @return {}
         * @author yyt
         * @date 2024/10/15
         **/
        @ApiId(1291)
        @PutMapping("/{id:\\d+}/guest-name")
        public Map updateGuestName(@PathVariable long id, String property, @Valid @RequestBody UpdateGuestNameDTO updateGuestNameDTO) {
            PastReservation pastReservation = pastReservationService.checkExist(id);
            int propertyId = sessionContext.getPropertyId(property);
            checkBelong(pastReservation, propertyId);
            checkEffective(pastReservation);

            if (pastReservationService.checkRepeat(propertyId, updateGuestNameDTO.getFirstName(), updateGuestNameDTO.getLastName(), id)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_EXISTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the pastReservation is existed");
            }

            pastReservationService.updateGuestName(pastReservation, updateGuestNameDTO, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 1292 - 保存入住记录
         *
         * @param id       连续入住数据 id
         * @param cid      入住记录 id
         * @param property 资产标识
         * @param dto      入住记录
         * @return {}
         * @author yyt
         * @date 2024/10/16
         **/
        @ApiId(1292)
        @PostMapping("/{id:\\d+}/check-in-record/{cid:\\d+}")
        public ShowRulesDTO saveCheckInRecord(@PathVariable long id, @PathVariable long cid, String property,
                                     @Validated(Edition.class) @RequestBody SaveCheckInRecordDTO dto) {
            Integer propertyId = sessionContext.getPropertyId(property);
            PastReservation pastReservation = pastReservationService.checkExist(id);
            checkBelong(pastReservation, propertyId);
            checkEffective(pastReservation);

            dto.setFirstName(pastReservation.getFirstName());
            dto.setLastName(pastReservation.getLastName());

            if (cid > BaseConstant.ZERO) {
                // 校验修改记录属于当前批次的连续入住记录里面的
                checkBelongPastReservation(pastReservation, cid);

                // 校验存在
                pastReservationOpGuestinHouseService.checkExist(cid);

                return pastReservationService.updateCheckInRecord(pastReservation, cid, dto, sessionContext.getLoginUserId());
            } else {
                return pastReservationService.saveCheckInRecord(pastReservation, dto, sessionContext.getLoginUserId());
            }
        }

        /**
         * 1293 - 删除入住记录
         *
         * @param id       连续入住数据 id
         * @param cid      入住记录 id
         * @param property 资产标识
         * @return {}
         * @author yyt
         * @date 2024/10/16
         **/
        @ApiId(1293)
        @DeleteMapping("/{id:\\d+}/check-in-record/{cid:\\d+}")
        public Map deleteCheckInRecord(@PathVariable long id, @PathVariable long cid, String property) {
            PastReservation pastReservation = pastReservationService.checkExist(id);
            checkBelong(pastReservation, sessionContext.getPropertyId(property));
            checkEffective(pastReservation);

            PastReservationOpGuestinHouse opGuestinHouse = pastReservationOpGuestinHouseService.checkExist(cid);

            // 校验入住记录属于当前批次的连续入住记录里面的
            checkBelongPastReservation(pastReservation, cid);

            return ImmutableMap.of("showGuest", pastReservationService.deleteCheckInRecord(pastReservation, opGuestinHouse, sessionContext.getLoginUserId()));
        }

        /**
         * 校验入住记录属于当前批次的连续入住记录里面的
         *
         * @param pastReservation 连续入住信息
         * @param cid             入住记录 id
         * @author yyt
         * @date 2024/10/16
         **/
        private void checkBelongPastReservation(PastReservation pastReservation, long cid) {
            if (!Arrays.stream(pastReservation.getMatchedIds().split(",")).map(Long::parseLong).toList().contains(cid)) {
                throw new BadRequestException(PastReservationErrorFiledCons.PAST_RESERVATION_NOT_MATCH,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The current modification record belongs to the continuous occupancy record of the current batch");
            }
        }

        /**
         * 1257 - 删除连续入住信息
         *
         * @param id       连续入住信息 id
         * @param property 资产标识
         * @return {}
         * @author yyt
         * @date 2024/10/2
         **/
        @ApiId(1257)
        @DeleteMapping("/{id:\\d+}")
        public Map delete(@PathVariable long id, String property) {
            PastReservation pastReservation = pastReservationService.checkExist(id);
            checkBelong(pastReservation, sessionContext.getPropertyId(property));
            checkEffective(pastReservation);

            pastReservationService.delete(pastReservation, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 1258 - 查询连续入住信息备注
         *
         * @param id   连续入住信息 id
         * @param page 页码
         * @param size 每页显示条数
         * @return {}
         * @author yyt
         * @date 2024/10/2
         **/
        @ApiId(1258)
        @GetMapping("/{id:\\d+}/comment")
        public ListPagedDTO<PastReservationCommentDTO> listComments(@PathVariable long id, int page, int size) {
            pastReservationService.checkExist(id);
            return pastReservationCommentService.listCommentDTO(sessionContext.getTenantSymbolBO().getId(), id, page, size);
        }

        /**
         * 1259 - 添加备注
         *
         * @param id       连续入住信息 id
         * @param property 资产标识
         * @param dto      备注信息
         * @return {}
         * @author yyt
         * @date 2024/10/2
         **/
        @ApiId(1259)
        @PostMapping("/{id:\\d+}/comment")
        public Map addComment(@PathVariable long id, String property, @Valid @RequestBody PastReservationCommentDTO dto) {
            PastReservation pastReservation = pastReservationService.checkExist(id);
            checkBelong(pastReservation, sessionContext.getPropertyId(property));

            pastReservationCommentService.addComment(pastReservation, dto, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 1260 - 删除备注
         *
         * @param id       备注 id
         * @param property 资产标识
         * @return {}
         * @author yyt
         * @date 2024/10/2
         **/
        @ApiId(1260)
        @DeleteMapping("/comment/{id:\\d+}")
        public Map deleteComment(@PathVariable long id, String property) {
            PastReservationComment comment = pastReservationCommentService.checkExist(id);

            PastReservation pastReservation = pastReservationService.checkExist(comment.getPtRsvId());
            checkBelong(pastReservation, sessionContext.getPropertyId(property));

            pastReservationCommentService.delete(id);

            return Collections.emptyMap();
        }

        /**
         * 1306 - 忽略 / 撤回
         *
         * @param id       连续入住信息 id
         * @param status   状态（1：正常显示，2：忽略）
         * @param property 资产标识
         * @return {}
         * @author yyt
         * @date 2024/11/7
         **/
        @ApiId(1306)
        @PutMapping("/{id:\\d+}/status/{status:\\d+}")
        public Map status(@PathVariable long id, @PathVariable int status, String property) {
            if (!Arrays.stream(PastReservationStatusEnum.values()).map(PastReservationStatusEnum::getCode).toList().contains(status)) {
                throw new BadRequestException(CommonErrorI18nConstant.MUST_IN_LIST,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CommonFieldI18nConstant.STATUS,
                                Arrays.stream(PastReservationStatusEnum.values()).map(PastReservationStatusEnum::getMsg).toList()),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the status is error");
            }

            PastReservation pastReservation = pastReservationService.checkExist(id);
            checkBelong(pastReservation, sessionContext.getPropertyId(property));
            checkEffective(pastReservation);

            pastReservationService.status(pastReservation, status, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 1269 - 获取导入记录
         *
         * @param property 资产标识
         * @param query 查询条件
         * @return 导入记录
         * @author yyt
         * @date 2024/10/3
         **/
        @ApiId(1269)
        @GetMapping("/import-log")
        public ListPagedDTO<ImportGuestInHouseLogDTO> listImportGuestInHouseLog(String property, @Valid GuestInHouseImportLogQuery query) {
            return pastReservationImportLogService.listImportGuestInHouseLogDTO(sessionContext.getTenantSymbolBO().getId(), sessionContext.getPropertyId(property), query);
        }

        /**
         * 1270 - 手动导入报告
         *
         * @param property              资产标识
         * @param importGuestInHouseDTO 选择条件
         * @return {}
         * @author yyt
         * @date 2023/7/28
         */
        @ApiId(1270)
        @PostMapping("/file")
        public Map importGuestInHouseReport(String property, @Valid ImportGuestInHouseDTO importGuestInHouseDTO) {
            SymbolBO tenant = sessionContext.getTenantSymbolBO();

            PropertyDTO propertyDTO = propertyI18nRedisService.get(sessionContext.getPropertyId(property));
            String pmsType = propertyDTO.getPmsType();
            //校验source是否符合预期
            if (!Lists.newArrayList(pmsType, SystemPlatformEnum.OTHER.getDesc()).contains(importGuestInHouseDTO.getSource())) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_SOURCE_SYSTEM_NOT_SUPPORTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The source must be in:" + pmsType + "|" + SystemPlatformEnum.OTHER.getDesc());
            }

            int userId = sessionContext.getLoginUserId();

            Map<String, IPastReservationReportParse> beans = applicationContext.getBeansOfType(IPastReservationReportParse.class);
            for (IPastReservationReportParse bean : beans.values()) {
                if (bean.supports(importGuestInHouseDTO.getSource(), importGuestInHouseDTO.getReportType())) {
                    bean.checkFile(propertyDTO, importGuestInHouseDTO.getFile());

                    PastReservationImportLog importLog = bean.handleImportLog(tenant, propertyDTO, importGuestInHouseDTO.getFile(), userId);

                    bean.handleFile(tenant, propertyDTO, importGuestInHouseDTO.getFile(), importLog, userId);
                    return Collections.emptyMap();
                }
            }

            return Collections.emptyMap();
        }

        /**
         * 校验数据归属
         *
         * @param pastReservation pastReservation
         * @param propertyId 资产 id
         * @author yyt
         * @date 2024/10/10
         */
        private void checkBelong(PastReservation pastReservation, Integer propertyId) {
            if (!pastReservation.getPropertyId().equals(propertyId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(), "the property id parameter is different from " +
                        "the property id of the pastReservation;propertyId:" + propertyId + ",pastReservationPropertyId:" + pastReservation.getPropertyId() +
                        ",pastReservationId:" + pastReservation.getId());
            }
        }

        /**
         * 已删除的数据不支持任何操作
         *
         * @param pastReservation 连续入住信息
         * @author yyt
         * @date 2024/10/15
         **/
        private void checkEffective(PastReservation pastReservation) {
            if (pastReservation.getDeleted()) {
                throw new BadRequestException(CommonErrorI18nConstant.DELETED_DATA_CANNOT_HANDLE,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "deleted data does not support any operation");
            }
        }

    }