doum
2026-06-18 93de43267e1663031fe5dc2f5ae40d128a182a76
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerDeviceAutoBindServiceImpl.java
@@ -2,10 +2,10 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.*;
import com.doumee.dao.business.dto.YwCustomerGsConfigDTO;
import com.doumee.dao.business.model.*;
@@ -13,6 +13,7 @@
import com.doumee.service.business.YwCustomerRechargeBizService;
import lombok.extern.slf4j.Slf4j;
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 org.springframework.util.CollectionUtils;
@@ -40,6 +41,7 @@
    @Autowired
    private YwConditionerMapper ywConditionerMapper;
    @Autowired
    @Lazy
    private YwCustomerRechargeBizService ywCustomerRechargeBizService;
    @Override
@@ -49,38 +51,52 @@
            return;
        }
        YwContract contract = ywContractMapper.selectById(contractId);
        if (contract == null || Objects.equals(contract.getIsdeleted(), Constants.ONE)) {
        if (contract == null || Objects.equals(contract.getIsdeleted(), Constants.ONE) || contract.getRenterId() == null) {
            return;
        }
        if (contract.getRenterId() == null) {
            return;
        }
        if (!isActiveContract(contract)) {
            return;
        }
        List<Integer> roomIds = listContractRoomIds(contractId);
        if (roomIds.isEmpty()) {
            return;
        }
        bindElectricals(contract, roomIds, user);
        bindConditioners(contract, roomIds, user);
        refreshCustomerDevices(contract.getRenterId(), user);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncByCustomerId(Integer customerId, LoginUserInfo user) {
        refreshCustomerDevices(customerId, user);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refreshCustomerDevices(Integer customerId, LoginUserInfo user) {
        if (customerId == null) {
            return;
        }
        LoginUserInfo opUser = user != null ? user : systemUser();
        List<YwContract> contracts = ywContractMapper.selectList(new QueryWrapper<YwContract>().lambda()
                .eq(YwContract::getRenterId, customerId)
                .eq(YwContract::getIsdeleted, Constants.ZERO)
                .in(YwContract::getStatus, Arrays.asList(Constants.ZERO, Constants.ONE, Constants.THREE)));
        for (YwContract c : contracts) {
            if (isActiveContract(c)) {
                syncByContractId(c.getId(), user);
                .eq(YwContract::getIsdeleted, Constants.ZERO));
        List<YwContract> activeContracts = contracts.stream().filter(this::isActiveContract).collect(Collectors.toList());
        Set<Integer> activeContractIds = activeContracts.stream().map(YwContract::getId).collect(Collectors.toSet());
        for (YwContract contract : contracts) {
            if (!activeContractIds.contains(contract.getId())) {
                unbindByContractId(contract.getId(), opUser);
            }
        }
        Set<Integer> roomIds = new LinkedHashSet<>();
        for (YwContract contract : activeContracts) {
            roomIds.addAll(listContractRoomIds(contract.getId()));
        }
        if (roomIds.isEmpty()) {
            clearContractElectricalBindings(customerId, opUser);
            softDeleteAllConditionerRels(customerId, opUser);
            return;
        }
        List<Integer> roomIdList = new ArrayList<>(roomIds);
        for (YwContract contract : activeContracts) {
            bindElectricals(contract, listContractRoomIds(contract.getId()), opUser);
        }
        bindConditionersMerged(customerId, roomIdList, opUser);
    }
    @Override
@@ -100,14 +116,153 @@
                .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO));
    }
    @Override
    public List<Integer> listActiveContractRoomIds(Integer customerId) {
        if (customerId == null) {
            return Collections.emptyList();
        }
        List<YwContract> active = listActiveContracts(customerId);
        Set<Integer> roomIds = new LinkedHashSet<>();
        for (YwContract contract : active) {
            roomIds.addAll(listContractRoomIds(contract.getId()));
        }
        return new ArrayList<>(roomIds);
    }
    @Override
    public List<Integer> listElectricalIdsByActiveContracts(Integer customerId) {
        List<Integer> roomIds = listActiveContractRoomIds(customerId);
        if (roomIds.isEmpty()) {
            return Collections.emptyList();
        }
        return new ArrayList<>(resolveElectricalIdsFromRooms(roomIds));
    }
    @Override
    public List<Integer> listConditionerIdsByActiveContracts(Integer customerId) {
        List<Integer> roomIds = listActiveContractRoomIds(customerId);
        if (roomIds.isEmpty()) {
            return Collections.emptyList();
        }
        return new ArrayList<>(resolveConditionerIdsFromRooms(roomIds));
    }
    @Override
    public Map<Integer, List<Integer>> batchListElectricalIdsByActiveContracts(List<Integer> customerIds) {
        return batchResolveDeviceIds(customerIds, Constants.ZERO);
    }
    @Override
    public Map<Integer, List<Integer>> batchListConditionerIdsByActiveContracts(List<Integer> customerIds) {
        return batchResolveDeviceIds(customerIds, Constants.ONE);
    }
    private Map<Integer, List<Integer>> batchResolveDeviceIds(List<Integer> customerIds, int deviceType) {
        if (CollectionUtils.isEmpty(customerIds)) {
            return Collections.emptyMap();
        }
        Map<Integer, Set<Integer>> roomsByCustomer = batchActiveContractRoomIds(customerIds);
        Set<Integer> allRoomIds = roomsByCustomer.values().stream()
                .flatMap(Set::stream).collect(Collectors.toCollection(LinkedHashSet::new));
        Map<Integer, Set<Integer>> devicesByRoom = mapDevicesByRoom(allRoomIds, deviceType);
        Map<Integer, List<Integer>> result = new LinkedHashMap<>();
        for (Integer customerId : customerIds) {
            Set<Integer> roomIds = roomsByCustomer.getOrDefault(customerId, Collections.emptySet());
            Set<Integer> deviceIds = new LinkedHashSet<>();
            for (Integer roomId : roomIds) {
                deviceIds.addAll(devicesByRoom.getOrDefault(roomId, Collections.emptySet()));
            }
            result.put(customerId, new ArrayList<>(deviceIds));
        }
        return result;
    }
    private Map<Integer, Set<Integer>> batchActiveContractRoomIds(List<Integer> customerIds) {
        List<YwContract> contracts = ywContractMapper.selectList(new QueryWrapper<YwContract>().lambda()
                .in(YwContract::getRenterId, customerIds)
                .eq(YwContract::getIsdeleted, Constants.ZERO));
        Map<Integer, List<YwContract>> activeByCustomer = contracts.stream()
                .filter(this::isActiveContract)
                .collect(Collectors.groupingBy(YwContract::getRenterId));
        List<Integer> contractIds = activeByCustomer.values().stream()
                .flatMap(List::stream).map(YwContract::getId).distinct().collect(Collectors.toList());
        Map<Integer, List<Integer>> roomsByContract = loadContractRoomMap(contractIds);
        Map<Integer, Set<Integer>> roomsByCustomer = new LinkedHashMap<>();
        for (Integer customerId : customerIds) {
            Set<Integer> roomIds = new LinkedHashSet<>();
            for (YwContract contract : activeByCustomer.getOrDefault(customerId, Collections.emptyList())) {
                roomIds.addAll(roomsByContract.getOrDefault(contract.getId(), Collections.emptyList()));
            }
            roomsByCustomer.put(customerId, roomIds);
        }
        return roomsByCustomer;
    }
    private Map<Integer, List<Integer>> loadContractRoomMap(List<Integer> contractIds) {
        if (CollectionUtils.isEmpty(contractIds)) {
            return Collections.emptyMap();
        }
        return ywContractRoomMapper.selectList(new QueryWrapper<YwContractRoom>().lambda()
                        .in(YwContractRoom::getContractId, contractIds)
                        .eq(YwContractRoom::getType, Constants.ZERO)
                        .eq(YwContractRoom::getIsdeleted, Constants.ZERO))
                .stream()
                .collect(Collectors.groupingBy(YwContractRoom::getContractId,
                        Collectors.mapping(YwContractRoom::getRoomId,
                                Collectors.collectingAndThen(Collectors.toList(),
                                        list -> list.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList())))));
    }
    private Map<Integer, Set<Integer>> mapDevicesByRoom(Set<Integer> roomIds, int deviceType) {
        if (CollectionUtils.isEmpty(roomIds)) {
            return Collections.emptyMap();
        }
        List<Integer> roomIdList = new ArrayList<>(roomIds);
        Map<Integer, Set<Integer>> result = new HashMap<>();
        List<YwElectricalRoom> relRooms = ywElectricalRoomMapper.selectList(new QueryWrapper<YwElectricalRoom>().lambda()
                .in(YwElectricalRoom::getRoomId, roomIdList)
                .eq(YwElectricalRoom::getType, deviceType)
                .eq(YwElectricalRoom::getIsdeleted, Constants.ZERO));
        for (YwElectricalRoom rel : relRooms) {
            if (rel.getRoomId() == null || rel.getObjId() == null) {
                continue;
            }
            result.computeIfAbsent(rel.getRoomId(), k -> new LinkedHashSet<>()).add(rel.getObjId());
        }
        if (deviceType == Constants.ONE) {
            List<YwConditioner> byRoom = ywConditionerMapper.selectList(new QueryWrapper<YwConditioner>().lambda()
                    .in(YwConditioner::getRoomId, roomIdList)
                    .eq(YwConditioner::getIsdeleted, Constants.ZERO));
            for (YwConditioner conditioner : byRoom) {
                if (conditioner.getRoomId() == null || conditioner.getId() == null) {
                    continue;
                }
                result.computeIfAbsent(conditioner.getRoomId(), k -> new LinkedHashSet<>()).add(conditioner.getId());
            }
        }
        return result;
    }
    private List<YwContract> listActiveContracts(Integer customerId) {
        return ywContractMapper.selectList(new QueryWrapper<YwContract>().lambda()
                        .eq(YwContract::getRenterId, customerId)
                        .eq(YwContract::getIsdeleted, Constants.ZERO))
                .stream().filter(this::isActiveContract).collect(Collectors.toList());
    }
    private boolean isActiveContract(YwContract contract) {
        if (contract.getStartDate() == null || contract.getEndDate() == null) {
        if (contract == null || contract.getStartDate() == null || contract.getEndDate() == null) {
            return false;
        }
        if (Objects.equals(contract.getStatus(), Constants.FOUR)) {
            return false;
        }
        long now = System.currentTimeMillis();
        return contract.getStartDate().getTime() <= now
                && contract.getEndDate().getTime() >= now
                && !Objects.equals(contract.getStatus(), Constants.FOUR);
                && Utils.Date.getEnd(contract.getEndDate()).getTime() >= now;
    }
    private List<Integer> listContractRoomIds(Integer contractId) {
@@ -119,13 +274,39 @@
                .collect(Collectors.toList());
    }
    private void bindElectricals(YwContract contract, List<Integer> roomIds, LoginUserInfo user) {
        List<YwElectricalRoom> relRooms = ywElectricalRoomMapper.selectList(new QueryWrapper<YwElectricalRoom>().lambda()
    private Set<Integer> resolveElectricalIdsFromRooms(List<Integer> roomIds) {
        if (CollectionUtils.isEmpty(roomIds)) {
            return Collections.emptySet();
        }
        return ywElectricalRoomMapper.selectList(new QueryWrapper<YwElectricalRoom>().lambda()
                        .in(YwElectricalRoom::getRoomId, roomIds)
                        .eq(YwElectricalRoom::getType, Constants.ZERO)
                        .eq(YwElectricalRoom::getIsdeleted, Constants.ZERO))
                .stream().map(YwElectricalRoom::getObjId).filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
    }
    private Set<Integer> resolveConditionerIdsFromRooms(List<Integer> roomIds) {
        if (CollectionUtils.isEmpty(roomIds)) {
            return Collections.emptySet();
        }
        Set<Integer> conditionerIds = new LinkedHashSet<>();
        List<YwElectricalRoom> acRooms = ywElectricalRoomMapper.selectList(new QueryWrapper<YwElectricalRoom>().lambda()
                .in(YwElectricalRoom::getRoomId, roomIds)
                .eq(YwElectricalRoom::getType, Constants.ZERO)
                .eq(YwElectricalRoom::getType, Constants.ONE)
                .eq(YwElectricalRoom::getIsdeleted, Constants.ZERO));
        Set<Integer> electricalIds = relRooms.stream().map(YwElectricalRoom::getObjId)
                .filter(Objects::nonNull).collect(Collectors.toCollection(LinkedHashSet::new));
        acRooms.stream().map(YwElectricalRoom::getObjId).filter(Objects::nonNull).forEach(conditionerIds::add);
        if (conditionerIds.isEmpty()) {
            ywConditionerMapper.selectList(new QueryWrapper<YwConditioner>().lambda()
                            .in(YwConditioner::getRoomId, roomIds)
                            .eq(YwConditioner::getIsdeleted, Constants.ZERO))
                    .stream().map(YwConditioner::getId).filter(Objects::nonNull).forEach(conditionerIds::add);
        }
        return conditionerIds;
    }
    private void bindElectricals(YwContract contract, List<Integer> roomIds, LoginUserInfo user) {
        Set<Integer> electricalIds = resolveElectricalIdsFromRooms(roomIds);
        if (electricalIds.isEmpty()) {
            return;
        }
@@ -142,7 +323,8 @@
                    .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)
                    .last("limit 1"));
            if (exist != null) {
                if (exist.getContractId() == null) {
                if (!Objects.equals(exist.getContractId(), contract.getId())
                        || !Objects.equals(exist.getBindSource(), BIND_SOURCE_CONTRACT)) {
                    exist.setContractId(contract.getId());
                    exist.setBindSource(BIND_SOURCE_CONTRACT);
                    exist.setEditDate(now);
@@ -165,24 +347,14 @@
        }
    }
    private void bindConditioners(YwContract contract, List<Integer> roomIds, LoginUserInfo user) {
        Set<Integer> conditionerIds = new LinkedHashSet<>();
        List<YwElectricalRoom> acRooms = ywElectricalRoomMapper.selectList(new QueryWrapper<YwElectricalRoom>().lambda()
                .in(YwElectricalRoom::getRoomId, roomIds)
                .eq(YwElectricalRoom::getType, Constants.ONE)
                .eq(YwElectricalRoom::getIsdeleted, Constants.ZERO));
        acRooms.stream().map(YwElectricalRoom::getObjId).filter(Objects::nonNull).forEach(conditionerIds::add);
    private void bindConditionersMerged(Integer customerId, List<Integer> roomIds, LoginUserInfo user) {
        Set<Integer> conditionerIds = resolveConditionerIdsFromRooms(roomIds);
        if (conditionerIds.isEmpty()) {
            List<YwConditioner> byRoom = ywConditionerMapper.selectList(new QueryWrapper<YwConditioner>().lambda()
                    .in(YwConditioner::getRoomId, roomIds)
                    .eq(YwConditioner::getIsdeleted, Constants.ZERO));
            byRoom.stream().map(YwConditioner::getId).forEach(conditionerIds::add);
        }
        if (conditionerIds.isEmpty()) {
            softDeleteAllConditionerRels(customerId, user);
            return;
        }
        YwCustomerGsConfigDTO dto = new YwCustomerGsConfigDTO();
        dto.setCustomerId(contract.getRenterId());
        dto.setCustomerId(customerId);
        dto.setIsPwr(Constants.ONE);
        dto.setIsRestStop(Constants.ZERO);
        dto.setGsBz("合同自动关联");
@@ -196,12 +368,33 @@
        }
        dto.setConditioners(items);
        try {
            ywCustomerRechargeBizService.saveCustomerGsConfig(dto, user != null ? user : systemUser());
            ywCustomerRechargeBizService.saveCustomerGsConfig(dto, user);
        } catch (BusinessException e) {
            log.warn("auto bind conditioner GS failed contractId={}: {}", contract.getId(), e.getMessage());
            log.warn("auto bind conditioner GS failed customerId={}: {}", customerId, e.getMessage());
        }
    }
    private void clearContractElectricalBindings(Integer customerId, LoginUserInfo user) {
        Date now = new Date();
        ywCustomerElectricalMapper.update(null, new UpdateWrapper<YwCustomerElectrical>().lambda()
                .set(YwCustomerElectrical::getIsdeleted, Constants.ONE)
                .set(YwCustomerElectrical::getEditDate, now)
                .set(YwCustomerElectrical::getEditor, user != null ? user.getId() : null)
                .eq(YwCustomerElectrical::getCustomerId, customerId)
                .eq(YwCustomerElectrical::getBindSource, BIND_SOURCE_CONTRACT)
                .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO));
    }
    private void softDeleteAllConditionerRels(Integer customerId, LoginUserInfo user) {
        Date now = new Date();
        ywCustomerConditionerMapper.update(null, new UpdateWrapper<YwCustomerConditioner>().lambda()
                .set(YwCustomerConditioner::getIsdeleted, Constants.ONE)
                .set(YwCustomerConditioner::getEditDate, now)
                .set(YwCustomerConditioner::getEditor, user != null ? user.getId() : null)
                .eq(YwCustomerConditioner::getCustomerId, customerId)
                .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO));
    }
    private Set<Integer> listBoundElectricalIdsExcept(Integer customerId) {
        List<YwCustomerElectrical> list = ywCustomerElectricalMapper.selectList(new QueryWrapper<YwCustomerElectrical>().lambda()
                .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)