# HkInventoryCategoryConfigServiceImpl.java

    package cloud.wconnect.workperformance.service.hkinventory.impl;

    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.commonlib.util.UpdateLogUtil;
    import cloud.wconnect.workperformance.cons.hkinventory.HkInventoryErrorI18nConstant;
    import cloud.wconnect.workperformance.cons.hkinventory.StatusEnum;
    import cloud.wconnect.workperformance.entity.hkinventory.HkInventory;
    import cloud.wconnect.workperformance.entity.hkinventory.HkInventoryCategory;
    import cloud.wconnect.workperformance.entity.hkinventory.HkInventoryCategoryConfig;
    import cloud.wconnect.workperformance.mapper.hkinventory.HkInventoryCategoryConfigMapper;
    import cloud.wconnect.workperformance.pojo.dto.hkinventory.HkInventoryCategoryConfigDTO;
    import cloud.wconnect.workperformance.service.hkinventory.*;
    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.fasterxml.jackson.databind.ObjectMapper;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    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.text.MessageFormat;
    import java.util.Collections;
    import java.util.List;
    import java.util.Objects;

    /**
     * <p>
     * 客房库存管理分类配置表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2025-04-19
     */
    @Service
    @DS("work_performance")
    public class HkInventoryCategoryConfigServiceImpl extends ServiceImpl<HkInventoryCategoryConfigMapper, HkInventoryCategoryConfig> implements IHkInventoryCategoryConfigService {

        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private UpdateLogUtil updateLogUtil;
        @Autowired
        @Lazy
        private IHkInventoryService hkInventoryService;
        @Autowired
        @Lazy
        private IHkInventoryCategoryService categoryService;
        @Autowired
        @Lazy
        private IHkInventoryRoomTypeService roomTypeService;
        @Autowired
        @Lazy
        private IHkInventoryPurchaseOrderService purchaseOrderService;
        @Autowired
        @Lazy
        private IHkInventoryItemService itemService;
        @Autowired
        @Lazy
        private IHkInventoryItemConfigService itemConfigService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;

        /**
         * 校验分类是否存在
         *
         * @param categoryId 分类id
         * @return cloud.wconnect.workperformance.entity.hkinventory.HkInventoryCategoryConfig
         * @author lichen
         * @date 2025/4/21
         */
        @Override
        public HkInventoryCategoryConfig checkExist(Integer categoryId) {
            HkInventoryCategoryConfig hkInventoryCategoryConfig = getOne(new LambdaQueryWrapper<HkInventoryCategoryConfig>().eq(HkInventoryCategoryConfig::getId, categoryId));
            if (Objects.isNull(hkInventoryCategoryConfig)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "Housekeeping Inventory category config not found,id=" + categoryId);
            }
            return hkInventoryCategoryConfig;
        }

        /**
         * 校验分类配置是否属于资产
         *
         * @param hkInventoryCategoryConfig 分类配置
         * @param propertyId                资产id
         * @return void
         * @author lichen
         * @date 2025/4/21
         */
        @Override
        public void checkBelong(HkInventoryCategoryConfig hkInventoryCategoryConfig, Integer propertyId) {
            if (!hkInventoryCategoryConfig.getPropertyId().equals(propertyId)) {
                throw new BadRequestException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(), BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The Housekeeping Inventory category config not belong currentPropertyId, hkInventoryCategoryConfigId:{0}, belongPropertyId:{1}, currentPropertyId:{2}",
                                hkInventoryCategoryConfig.getId(), hkInventoryCategoryConfig.getPropertyId(), propertyId));
            }
        }

        /**
         * 校验分类配置是否包含指定房型
         *
         * @param hkInventoryCategoryConfig 分类配置
         * @param roomTypeId                房型id
         * @return void
         * @author lichen
         * @date 2025/4/21
         */
        @Override
        public void checkContainRoomType(HkInventoryCategoryConfig hkInventoryCategoryConfig, Integer roomTypeId) {
            List<Integer> roomTypeIds = JsonUtils.convertStringToList(objectMapper, hkInventoryCategoryConfig.getRoomTypeIds(), Integer.class);
            if (!roomTypeIds.contains(roomTypeId)) {
                throw new BadRequestException(HkInventoryErrorI18nConstant.ROOM_TYPE_NOT_BELONGS_TO_CATEGORY,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The Housekeeping Inventory category config not contain currentRoomTypeId, hkInventoryCategoryConfigId:{0}, contailRoomTypeIds:{1}, currentRoomTypeId:{2}",
                                hkInventoryCategoryConfig.getId(), hkInventoryCategoryConfig.getRoomTypeIds(), roomTypeId));
            }
        }

        /**
         * 根据分类名称查询
         *
         * @param propertyId   资产id
         * @param categoryName 分类名称
         * @return java.util.List<cloud.wconnect.workperformance.entity.hkinventory.HkInventoryCategoryConfig>
         * @author lichen
         * @date 2025/4/22
         */
        @Override
        public List<HkInventoryCategoryConfig> listByName(Integer propertyId, String categoryName) {
            return list(new LambdaQueryWrapper<HkInventoryCategoryConfig>()
                    .eq(HkInventoryCategoryConfig::getPropertyId, propertyId)
                    .eq(StringUtils.isNotBlank(categoryName), HkInventoryCategoryConfig::getCategoryName, categoryName)
                    .orderByDesc(HkInventoryCategoryConfig::getId));
        }

        /**
         * 校验分类名称是否重复
         *
         * @param propertyId   资产id
         * @param categoryName 分类名称
         * @param categoryId   分类id
         * @return void
         * @author lichen
         * @date 2025/4/22
         */
        @Override
        public void checkNameRepeat(Integer propertyId, String categoryName, Integer categoryId) {
            long count = count(new LambdaQueryWrapper<HkInventoryCategoryConfig>()
                    .eq(HkInventoryCategoryConfig::getPropertyId, propertyId)
                    .eq(HkInventoryCategoryConfig::getCategoryName, categoryName)
                    .ne(categoryId > 0, HkInventoryCategoryConfig::getId, categoryId));
            if (count > 0) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_EXISTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The Housekeeping Inventory category config name already exists, propertyId:{0}, categoryName:{1}",
                                propertyId, categoryName));
            }
        }

        /**
         * 新增客房库存管理分类配置表
         *
         * @param propertyId        资产id
         * @param categoryConfigDTO 新增的分类配置DTO
         * @param loginUserId       用户id
         * @return java.lang.Integer
         * @author lichen
         * @date 2025/4/22
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Integer insert(int propertyId, HkInventoryCategoryConfigDTO categoryConfigDTO, int loginUserId) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //新增分类配置
            HkInventoryCategoryConfig hkInventoryCategoryConfig = new HkInventoryCategoryConfig();
            hkInventoryCategoryConfig.setTenantId(propertyDTO.getTenantId());
            hkInventoryCategoryConfig.setPropertyId(propertyId);
            hkInventoryCategoryConfig.setCategoryName(categoryConfigDTO.getCategoryName());
            hkInventoryCategoryConfig.setRoomTypeIds(JsonUtils.convertObjListToString(objectMapper, categoryConfigDTO.getAddRoomTypeIds()));
            hkInventoryCategoryConfig.setUpdateLog(updateLogUtil.get(loginUserId));
            save(hkInventoryCategoryConfig);

            //未发布的客房库存管理
            List<HkInventory> hkInventoryList = hkInventoryService.listByStatus(propertyId, StatusEnum.PENDING.getStatus());
            if (CollectionUtils.isNotEmpty(hkInventoryList)) {
                List<Integer> hkInventoryIds = hkInventoryList.stream().map(HkInventory::getId).toList();
                //初始化分类
                initCategory(propertyDTO, hkInventoryIds, hkInventoryCategoryConfig);
                //初始化房型
                roomTypeService.initRoomType(propertyDTO, hkInventoryIds, hkInventoryCategoryConfig, categoryConfigDTO.getAddRoomTypeIds());
            }
            return hkInventoryCategoryConfig.getId();
        }

        /**
         * 初始化分类
         *
         * @param propertyDTO               资产DTO
         * @param hkInventoryIds            Housekeeping Inventory Id集合
         * @param hkInventoryCategoryConfig 分类配置
         * @return void
         * @author lichen
         * @date 2025/5/9
         */
        private void initCategory(PropertyDTO propertyDTO, List<Integer> hkInventoryIds, HkInventoryCategoryConfig hkInventoryCategoryConfig) {
            if (CollectionUtils.isEmpty(hkInventoryIds)) return;

            List<HkInventoryCategory> categoryList = hkInventoryIds.stream().map(hkInventoryId -> {
                HkInventoryCategory hkInventoryCategory = new HkInventoryCategory();
                hkInventoryCategory.setTenantId(propertyDTO.getTenantId());
                hkInventoryCategory.setPropertyId(propertyDTO.getId());
                hkInventoryCategory.setHkInventoryId(hkInventoryId);
                hkInventoryCategory.setCategoryId(hkInventoryCategoryConfig.getId());
                hkInventoryCategory.setCategoryName(hkInventoryCategoryConfig.getCategoryName());
                return hkInventoryCategory;
            }).toList();
            categoryService.saveBatch(categoryList);
        }

        /**
         * 更新分类配置
         *
         * @param propertyId        资产id
         * @param oriCategoryConfig 原分类配置
         * @param categoryConfigDTO 更新的分类配置DTO
         * @param loginUserId       用户id
         * @return void
         * @author lichen
         * @date 2025/4/22
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(int propertyId, HkInventoryCategoryConfig oriCategoryConfig, HkInventoryCategoryConfigDTO categoryConfigDTO, int loginUserId) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //修改前的房型id集合
            List<Integer> oriRoomTypeIds = JsonUtils.convertStringToList(objectMapper, oriCategoryConfig.getRoomTypeIds(), Integer.class);

            HkInventoryCategoryConfig updateEntity = new HkInventoryCategoryConfig();
            updateEntity.setId(oriCategoryConfig.getId());
            updateEntity.setCategoryName(categoryConfigDTO.getCategoryName());

            List<Integer> addRoomTypeIds = categoryConfigDTO.getAddRoomTypeIds();
            oriRoomTypeIds.addAll(addRoomTypeIds);

            List<Integer> deleteRoomTypeIds = categoryConfigDTO.getDeleteRoomTypeIds();
            oriRoomTypeIds.removeAll(deleteRoomTypeIds);
            //设置房型ids
            updateEntity.setRoomTypeIds(JsonUtils.convertObjListToString(objectMapper, oriRoomTypeIds));
            //设置更新日志
            updateEntity.setUpdateLog(updateLogUtil.append(oriCategoryConfig.getUpdateLog(), loginUserId));
            //更新分类
            updateById(updateEntity);

            if (!oriCategoryConfig.getCategoryName().equals(categoryConfigDTO.getCategoryName())) {
                //更新客房库存管理-分类表
                categoryService.updateCategoryNameByCategoryId(propertyId, oriCategoryConfig.getId(), categoryConfigDTO.getCategoryName());
                //更新客房库存管理-采购订单表
                purchaseOrderService.updateCategoryNameByCategoryId(propertyId, oriCategoryConfig.getId(), categoryConfigDTO.getCategoryName());
            }

            //删除指定分类指定房型下的item配置
            itemConfigService.deleteByCategoryIdAndRoomTypeIds(propertyId, oriCategoryConfig.getId(), deleteRoomTypeIds);

            //未发布的客房库存管理
            List<HkInventory> hkInventoryList = hkInventoryService.listByStatus(propertyId, StatusEnum.PENDING.getStatus());
            if (CollectionUtils.isEmpty(hkInventoryList)) return;
            List<Integer> hkInventoryIds = hkInventoryList.stream().map(HkInventory::getId).toList();

            //初始化房型
            roomTypeService.initRoomType(propertyDTO, hkInventoryIds, updateEntity, addRoomTypeIds);

            //删除指定Housekeeping Inventory指定分类下关联的房型
            roomTypeService.deleteByHkInventoryIdsAndCategoryIdAndRoomTypeIds(propertyId, hkInventoryIds,
                    oriCategoryConfig.getId(), deleteRoomTypeIds);

            //删除指定Housekeeping Inventory指定分类指定房型下的item
            itemService.deleteByHkInventoryIdsAndCategoryIdAndRoomTypeIds(propertyId, hkInventoryIds,
                    oriCategoryConfig.getId(), deleteRoomTypeIds);
        }

        /**
         * 删除分类配置
         *
         * @param propertyId     资产id
         * @param categoryConfig 分类配置
         * @return void
         * @author lichen
         * @date 2025/4/22
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void delete(int propertyId, HkInventoryCategoryConfig categoryConfig) {
            //删除分类配置
            removeById(categoryConfig.getId());
            //删除分类下的item配置
            itemConfigService.deleteByCategoryId(propertyId, categoryConfig.getId());

            //分类下的房型ids
            List<Integer> roomTypeIds = JsonUtils.convertStringToList(objectMapper, categoryConfig.getRoomTypeIds(), Integer.class);
            if (CollectionUtils.isEmpty(roomTypeIds)) return;

            //查询未发布的客房库存管理
            List<HkInventory> hkInventoryList = hkInventoryService.listByStatus(propertyId, StatusEnum.PENDING.getStatus());
            if (CollectionUtils.isEmpty(hkInventoryList)) return;
            List<Integer> hkInventoryIds = hkInventoryList.stream().map(HkInventory::getId).toList();
            //删除指定Housekeeping Inventory指定分类的数据
            categoryService.deleteByHkInventoryIdsAndCategoryId(propertyId, hkInventoryIds, categoryConfig.getId());
            //删除指定Housekeeping Inventory指定分类下关联的房型
            roomTypeService.deleteByHkInventoryIdsAndCategoryIdAndRoomTypeIds(propertyId, hkInventoryIds,
                    categoryConfig.getId(), roomTypeIds);
            //删除指定Housekeeping Inventory指定分类指定房型下的item
            itemService.deleteByHkInventoryIdsAndCategoryIdAndRoomTypeIds(propertyId, hkInventoryIds, categoryConfig.getId(), roomTypeIds);
        }

        /**
         * 查询分类配置
         *
         * @param propertyIds 资产id集合
         * @return java.util.List<cloud.wconnect.workperformance.entity.hkinventory.HkInventoryCategoryConfig>
         * @author lichen
         * @date 2025/4/25
         */
        @Override
        public List<HkInventoryCategoryConfig> listByPropertyIds(List<Integer> propertyIds) {
            if (CollectionUtils.isEmpty(propertyIds)) return Collections.emptyList();
            return list(new LambdaQueryWrapper<HkInventoryCategoryConfig>().in(HkInventoryCategoryConfig::getPropertyId, propertyIds));
        }

        /**
         * 删除分类中关联的该房型
         *
         * @param propertyId       资产id
         * @param deleteRoomTypeId 删除的房型id
         * @return void
         * @author lichen
         * @date 2025/4/28
         */
        @Override
        public void removeCategoryRelateRoomTypeId(Integer propertyId, Integer deleteRoomTypeId) {
            List<HkInventoryCategoryConfig> categoryConfigList = list(new LambdaQueryWrapper<HkInventoryCategoryConfig>().eq(HkInventoryCategoryConfig::getPropertyId, propertyId)
                    .apply("JSON_CONTAINS(room_type_ids, {0})", deleteRoomTypeId.toString()));
            if (CollectionUtils.isEmpty(categoryConfigList)) return;

            categoryConfigList.forEach(categoryConfig -> {
                List<Integer> roomTypeIds = JsonUtils.convertStringToList(objectMapper, categoryConfig.getRoomTypeIds(), Integer.class);
                roomTypeIds.remove(deleteRoomTypeId);
                categoryConfig.setRoomTypeIds(JsonUtils.convertObjListToString(objectMapper, roomTypeIds));
            });

            //批量更新
            updateBatchById(categoryConfigList);
        }
    }