# HkInventoryItemConfigServiceImpl.java

    package cloud.wconnect.workperformance.service.hkinventory.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.pojo.dto.ListPagedDTO;
    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.*;
    import cloud.wconnect.workperformance.mapper.hkinventory.HkInventoryItemConfigMapper;
    import cloud.wconnect.workperformance.pojo.dto.hkinventory.HkInventoryItemConfigDTO;
    import cloud.wconnect.workperformance.pojo.query.hkinventory.HkInventoryItemConfigQuery;
    import cloud.wconnect.workperformance.pojo.vo.hkinventory.HkInventoryItemConfigVO;
    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.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.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.math.BigDecimal;
    import java.text.MessageFormat;
    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 客房库存管理-物品配置表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2025-04-19
     */
    @Service
    @DS("work_performance")
    public class HkInventoryItemConfigServiceImpl extends ServiceImpl<HkInventoryItemConfigMapper, HkInventoryItemConfig> implements IHkInventoryItemConfigService {

        @Autowired
        @Lazy
        private IHkInventoryPurchaseOrderService purchaseOrderService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        @Lazy
        private IHkInventoryItemService itemService;
        @Autowired
        private UpdateLogUtil updateLogUtil;
        @Autowired
        @Lazy
        private IHkInventoryService hkInventoryService;
        @Autowired
        @Lazy
        private IHkInventoryCategoryConfigService categoryConfigService;
        @Autowired
        @Lazy
        private IHkInventoryRoomTypeConfigService roomTypeConfigService;

        /**
         * 查询指定分类指定房型下的item配置列表
         *
         * @param propertyId      资产id
         * @param itemConfigQuery 查询对象
         * @return cloud.wconnect.commonlib.pojo.dto.ListPagedDTO<cloud.wconnect.workperformance.pojo.vo.hkinventory.HkInventoryItemConfigVO>
         * @author lichen
         * @date 2025/4/22
         */
        @Override
        public ListPagedDTO<HkInventoryItemConfigVO> pageByCategoryIdAndRoomTypeId(int propertyId, HkInventoryItemConfigQuery itemConfigQuery) {
            LambdaQueryWrapper<HkInventoryItemConfig> lambdaQueryWrapper = new LambdaQueryWrapper<HkInventoryItemConfig>().eq(HkInventoryItemConfig::getPropertyId, propertyId)
                    .eq(Objects.nonNull(itemConfigQuery.getCategoryId()), HkInventoryItemConfig::getCategoryId, itemConfigQuery.getCategoryId())
                    .eq(Objects.nonNull(itemConfigQuery.getRoomTypeId()), HkInventoryItemConfig::getRoomTypeId, itemConfigQuery.getRoomTypeId());

            List<HkInventoryItemConfig> records;
            long total;
            if (Objects.nonNull(itemConfigQuery.getPage()) && Objects.nonNull(itemConfigQuery.getSize())) {
                Page<HkInventoryItemConfig> itemConfigPage = page(new Page<>(itemConfigQuery.getPage(), itemConfigQuery.getSize()),
                        lambdaQueryWrapper.like(StringUtils.isNotBlank(itemConfigQuery.getItemName()), HkInventoryItemConfig::getItemName, itemConfigQuery.getItemName())
                                .orderByDesc(HkInventoryItemConfig::getId));
                records = itemConfigPage.getRecords();
                total = itemConfigPage.getTotal();
            } else {
                records = list(lambdaQueryWrapper.eq(StringUtils.isNotBlank(itemConfigQuery.getItemName()), HkInventoryItemConfig::getItemName, itemConfigQuery.getItemName())
                        .orderByDesc(HkInventoryItemConfig::getId));
                total = records.size();
            }
            if (total == 0L) return new ListPagedDTO<>();

            List<HkInventoryItem> items = records.stream().map(itemConfig -> {
                HkInventoryItem item = new HkInventoryItem();
                item.setCategoryId(itemConfig.getCategoryId());
                item.setRoomTypeId(itemConfig.getRoomTypeId());
                item.setItemId(itemConfig.getId());
                return item;
            }).toList();
            //指定分类指定房型下的item最新订单
            Map<String, BigDecimal> categoryIdAndRoomTypeIdAndItemId2OrderId = purchaseOrderService.listItemsLatestPurchaseOrder(propertyId, items).stream()
                    .collect(Collectors.toMap(HkInventoryPurchaseOrder::generateKey, HkInventoryPurchaseOrder::getUnitCost, (v1, v2) -> v1));

            //分类名称
            List<Integer> categoryIds = records.stream().map(HkInventoryItemConfig::getCategoryId).toList();
            Map<Integer, String> categoryId2Name = categoryConfigService.listByIds(categoryIds).stream()
                    .collect(Collectors.toMap(HkInventoryCategoryConfig::getId, HkInventoryCategoryConfig::getCategoryName));

            //房型名称
            List<Integer> roomTypeIds = records.stream().map(HkInventoryItemConfig::getRoomTypeId).toList();
            Map<Integer, String> roomTypeId2Name = roomTypeConfigService.listByIds(roomTypeIds).stream()
                    .collect(Collectors.toMap(HkInventoryRoomTypeConfig::getId, HkInventoryRoomTypeConfig::getRoomTypeName));

            return new ListPagedDTO<>(total, beanMapper.mapList(records, HkInventoryItemConfigVO.class, (entity, vo) -> {
                String key = String.format("%s_%s_%s", entity.getCategoryId(), entity.getRoomTypeId(), entity.getId());
                BigDecimal purchaseOrderUnitCost = categoryIdAndRoomTypeIdAndItemId2OrderId.get(key);
                vo.setPurchaseOrderUnitCost(purchaseOrderUnitCost);
                vo.setCategoryName(categoryId2Name.get(entity.getCategoryId()));
                vo.setRoomTypeName(roomTypeId2Name.get(entity.getRoomTypeId()));
            }));
        }

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

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

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

        /**
         * 修改item配置
         *
         * @param propertyId    资产id
         * @param oriItemConfig 修改前的item config
         * @param itemConfigDTO 修改后的item DTO
         * @param loginUserId   登录用户id
         * @return void
         * @author lichen
         * @date 2025/4/23
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(int propertyId, HkInventoryItemConfig oriItemConfig, HkInventoryItemConfigDTO itemConfigDTO, Integer loginUserId) {
            //修改item config
            HkInventoryItemConfig updateEntity = beanMapper.map(itemConfigDTO, HkInventoryItemConfig.class);
            updateEntity.setId(oriItemConfig.getId());
            updateEntity.setUpdateLog(updateLogUtil.append(oriItemConfig.getUpdateLog(), loginUserId));
            updateById(updateEntity);

            if (!oriItemConfig.getItemName().equals(itemConfigDTO.getItemName())) {
                //更新客房库存管理-item表
                itemService.updateItemNameByCategoryIdAndRoomTypeIdAndItemId(propertyId, oriItemConfig.getCategoryId(), oriItemConfig.getRoomTypeId(),
                        oriItemConfig.getId(), itemConfigDTO.getItemName());
                //更新客房库存管理-采购订单表
                purchaseOrderService.updateItemNameByCategoryIdAndRoomTypeIdAndItemId(propertyId, oriItemConfig.getCategoryId(), oriItemConfig.getRoomTypeId(),
                        oriItemConfig.getId(), itemConfigDTO.getItemName());
            }

            if (!oriItemConfig.getMinPerRoom().equals(itemConfigDTO.getMinPerRoom())
                    || !oriItemConfig.getParTarget().equals(itemConfigDTO.getParTarget())
                    || !oriItemConfig.getUnitCost().equals(itemConfigDTO.getUnitCost())) {
                //查询未发布的客房库存管理
                List<HkInventory> hkInventoryList = hkInventoryService.listByStatus(propertyId, StatusEnum.PENDING.getStatus());
                //如果没有未发布客房库存管理，则不需要更新minPerRoom或parTarget
                if (CollectionUtils.isEmpty(hkInventoryList)) return;
                List<Integer> hkInventoryIds = hkInventoryList.stream().map(HkInventory::getId).toList();
                //查询item数据
                List<HkInventoryItem> hkInventoryItems = itemService.listByHkInventoryIdsAndCategoryIdAndRoomTypeIdAndItemId(propertyId, hkInventoryIds,
                        oriItemConfig.getCategoryId(), oriItemConfig.getRoomTypeId(), oriItemConfig.getId());
                for (HkInventoryItem hkInventoryItem : hkInventoryItems) {
                    hkInventoryItem.setMinPerRoom(itemConfigDTO.getMinPerRoom());
                    hkInventoryItem.setParTarget(itemConfigDTO.getParTarget());
                    hkInventoryItem.setUnitCost(itemConfigDTO.getUnitCost());
                }
                //更新
                itemService.updateBatchById(hkInventoryItems);
            }
        }

        /**
         * 新增item配置
         *
         * @param tenantId                 租户id
         * @param propertyId               资产id
         * @param hkInventoryItemConfigDTO 新增的item DTO
         * @param loginUserId              登录用户id
         * @return java.lang.Integer
         * @author lichen
         * @date 2025/4/23
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Integer insert(Integer tenantId, int propertyId, HkInventoryItemConfigDTO hkInventoryItemConfigDTO, int loginUserId) {
            //新增item config
            HkInventoryItemConfig itemConfig = beanMapper.map(hkInventoryItemConfigDTO, HkInventoryItemConfig.class);
            itemConfig.setTenantId(tenantId);
            itemConfig.setPropertyId(propertyId);
            itemConfig.setUpdateLog(updateLogUtil.get(loginUserId));
            save(itemConfig);

            //查询未发布的客房库存管理
            List<HkInventory> hkInventoryList = hkInventoryService.listByStatus(propertyId, StatusEnum.PENDING.getStatus());
            //未发布客房库存管理，需要初始化数据
            if (CollectionUtils.isNotEmpty(hkInventoryList)) {
                initData(tenantId, propertyId, hkInventoryList, itemConfig, loginUserId);
            }
            return itemConfig.getId();
        }

        /**
         * 删除item配置
         *
         * @param propertyId 资产id
         * @param itemConfig item配置
         * @return void
         * @author lichen
         * @date 2025/4/23
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void delete(int propertyId, HkInventoryItemConfig itemConfig) {
            //删除item配置
            removeById(itemConfig.getId());

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

            //查询指定客房库存所有分类指定房型下的item数据
            List<HkInventoryItem> hkInventoryItems = itemService.listByHkInventoryIdsAndCategoryIdAndRoomTypeIdAndItemId(propertyId, hkInventoryIds,
                    itemConfig.getCategoryId(), itemConfig.getRoomTypeId(), itemConfig.getId());
            if (CollectionUtils.isEmpty(hkInventoryItems)) return;
            //删除item数据
            itemService.removeByIds(hkInventoryItems.stream().map(HkInventoryItem::getId).toList());
        }

        /**
         * 校验item是否归属于房型
         *
         * @param itemConfig item配置
         * @param roomTypeId 房型id
         * @return void
         * @author lichen
         * @date 2025/4/23
         */
        @Override
        public void checkBelongRoomType(HkInventoryItemConfig itemConfig, Integer roomTypeId) {
            if (!itemConfig.getRoomTypeId().equals(roomTypeId)) {
                throw new BadRequestException(HkInventoryErrorI18nConstant.ITEM_NOT_BELONG_TO_CURRENT_ROOM_TYPE,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The Housekeeping Inventory item config not belong currentRoomTypeId, itemConfigId:{0}, belongRoomTypeId:{1}, currentRoomTypeId:{2}",
                                itemConfig.getId(), itemConfig.getRoomTypeId(), roomTypeId));
            }
        }

        /**
         * 校验item是否归属于分类
         *
         * @param itemConfig item配置
         * @param categoryId 分类id
         * @return void
         * @author lichen
         * @date 2025/4/23
         */
        @Override
        public void checkBelongCategory(HkInventoryItemConfig itemConfig, Integer categoryId) {
            if (!itemConfig.getCategoryId().equals(categoryId)) {
                throw new BadRequestException(HkInventoryErrorI18nConstant.ITEM_NOT_BELONG_TO_CURRENT_CATEGORY
                        , BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The Housekeeping Inventory item config not belong currentCategoryId, itemConfigId:{0}, belongCategoryId:{1}, currentCategoryId:{2}",
                                itemConfig.getId(), itemConfig.getCategoryId(), categoryId));
            }
        }

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

        /**
         * 删除房型下的item配置
         *
         * @param propertyId 资产id
         * @param roomTypeId 房型id
         * @return void
         * @author lichen
         * @date 2025/4/28
         */
        @Override
        public void deleteByRoomTypeId(Integer propertyId, Integer roomTypeId) {
            remove(new LambdaQueryWrapper<HkInventoryItemConfig>().eq(HkInventoryItemConfig::getPropertyId, propertyId)
                    .eq(HkInventoryItemConfig::getRoomTypeId, roomTypeId));
        }

        /**
         * 删除指定分类指定房型下的item配置
         *
         * @param propertyId  资产id
         * @param categoryId  分类id
         * @param roomTypeIds 房型id
         * @return void
         * @author lichen
         * @date 2025/4/28
         */
        @Override
        public void deleteByCategoryIdAndRoomTypeIds(Integer propertyId, Integer categoryId, List<Integer> roomTypeIds) {
            if (CollectionUtils.isEmpty(roomTypeIds)) return;
            remove(new LambdaQueryWrapper<HkInventoryItemConfig>().eq(HkInventoryItemConfig::getPropertyId, propertyId)
                    .eq(HkInventoryItemConfig::getCategoryId, categoryId)
                    .in(HkInventoryItemConfig::getRoomTypeId, roomTypeIds));
        }

        /**
         * 删除分类下的item配置
         *
         * @param propertyId 资产id
         * @param categoryId 分类id
         * @return void
         * @author lichen
         * @date 2025/4/28
         */
        @Override
        public void deleteByCategoryId(Integer propertyId, Integer categoryId) {
            remove(new LambdaQueryWrapper<HkInventoryItemConfig>().eq(HkInventoryItemConfig::getPropertyId, propertyId)
                    .eq(HkInventoryItemConfig::getCategoryId, categoryId));
        }

        /**
         * 初始化数据
         *
         * @param tenantId        租户id
         * @param propertyId      资产id
         * @param hkInventoryList 客房库存管理集合
         * @param itemConfig      item配置
         * @return void
         * @author lichen
         * @date 2025/4/23
         */
        private void initData(Integer tenantId, int propertyId, List<HkInventory> hkInventoryList, HkInventoryItemConfig itemConfig, int loginUserId) {
            ArrayList<HkInventoryItem> itemList = Lists.newArrayListWithCapacity(hkInventoryList.size());
            for (HkInventory hkInventory : hkInventoryList) {
                HkInventoryItem hkInventoryItem = new HkInventoryItem();
                hkInventoryItem.setTenantId(tenantId);
                hkInventoryItem.setPropertyId(propertyId);
                hkInventoryItem.setHkInventoryId(hkInventory.getId());
                hkInventoryItem.setCategoryId(itemConfig.getCategoryId());
                hkInventoryItem.setRoomTypeId(itemConfig.getRoomTypeId());
                hkInventoryItem.setItemId(itemConfig.getId());
                hkInventoryItem.setItemName(itemConfig.getItemName());
                hkInventoryItem.setMinPerRoom(itemConfig.getMinPerRoom());
                hkInventoryItem.setParTarget(itemConfig.getParTarget());
                hkInventoryItem.setUnitCost(itemConfig.getUnitCost());
                hkInventoryItem.setPurchaseOrderId(0);
                hkInventoryItem.setUpdateLog(updateLogUtil.get(loginUserId));
                itemList.add(hkInventoryItem);
            }
            itemService.saveBatch(itemList);
        }
    }