package com.doumee.service.business.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; 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.*; import com.doumee.service.business.YwCustomerDeviceAutoBindService; 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; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @Service @Slf4j public class YwCustomerDeviceAutoBindServiceImpl implements YwCustomerDeviceAutoBindService { private static final int BIND_SOURCE_CONTRACT = 1; @Autowired private YwContractMapper ywContractMapper; @Autowired private YwContractRoomMapper ywContractRoomMapper; @Autowired private YwElectricalRoomMapper ywElectricalRoomMapper; @Autowired private YwCustomerElectricalMapper ywCustomerElectricalMapper; @Autowired private YwCustomerConditionerMapper ywCustomerConditionerMapper; @Autowired private YwConditionerMapper ywConditionerMapper; @Autowired @Lazy private YwCustomerRechargeBizService ywCustomerRechargeBizService; @Override @Transactional(rollbackFor = Exception.class) public void syncByContractId(Integer contractId, LoginUserInfo user) { if (contractId == null) { return; } YwContract contract = ywContractMapper.selectById(contractId); if (contract == null || Objects.equals(contract.getIsdeleted(), Constants.ONE) || contract.getRenterId() == null) { return; } 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 contracts = ywContractMapper.selectList(new QueryWrapper().lambda() .eq(YwContract::getRenterId, customerId) .eq(YwContract::getIsdeleted, Constants.ZERO)); List activeContracts = contracts.stream().filter(this::isActiveContract).collect(Collectors.toList()); Set activeContractIds = activeContracts.stream().map(YwContract::getId).collect(Collectors.toSet()); for (YwContract contract : contracts) { if (!activeContractIds.contains(contract.getId())) { unbindByContractId(contract.getId(), opUser); } } Set roomIds = new LinkedHashSet<>(); for (YwContract contract : activeContracts) { roomIds.addAll(listContractRoomIds(contract.getId())); } if (roomIds.isEmpty()) { clearContractElectricalBindings(customerId, opUser); softDeleteAllConditionerRels(customerId, opUser); return; } List roomIdList = new ArrayList<>(roomIds); for (YwContract contract : activeContracts) { bindElectricals(contract, listContractRoomIds(contract.getId()), opUser); } bindConditionersMerged(customerId, roomIdList, opUser); } @Override @Transactional(rollbackFor = Exception.class) public void unbindByContractId(Integer contractId, LoginUserInfo user) { if (contractId == null) { return; } Date now = new Date(); Integer editor = user != null ? user.getId() : null; ywCustomerElectricalMapper.update(null, new UpdateWrapper().lambda() .set(YwCustomerElectrical::getIsdeleted, Constants.ONE) .set(YwCustomerElectrical::getEditDate, now) .set(YwCustomerElectrical::getEditor, editor) .eq(YwCustomerElectrical::getContractId, contractId) .eq(YwCustomerElectrical::getBindSource, BIND_SOURCE_CONTRACT) .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)); } @Override public List listActiveContractRoomIds(Integer customerId) { if (customerId == null) { return Collections.emptyList(); } List active = listActiveContracts(customerId); Set roomIds = new LinkedHashSet<>(); for (YwContract contract : active) { roomIds.addAll(listContractRoomIds(contract.getId())); } return new ArrayList<>(roomIds); } @Override public List listElectricalIdsByActiveContracts(Integer customerId) { List roomIds = listActiveContractRoomIds(customerId); if (roomIds.isEmpty()) { return Collections.emptyList(); } return new ArrayList<>(resolveElectricalIdsFromRooms(roomIds)); } @Override public List listConditionerIdsByActiveContracts(Integer customerId) { List roomIds = listActiveContractRoomIds(customerId); if (roomIds.isEmpty()) { return Collections.emptyList(); } return new ArrayList<>(resolveConditionerIdsFromRooms(roomIds)); } @Override public Map> batchListElectricalIdsByActiveContracts(List customerIds) { return batchResolveDeviceIds(customerIds, Constants.ZERO); } @Override public Map> batchListConditionerIdsByActiveContracts(List customerIds) { return batchResolveDeviceIds(customerIds, Constants.ONE); } private Map> batchResolveDeviceIds(List customerIds, int deviceType) { if (CollectionUtils.isEmpty(customerIds)) { return Collections.emptyMap(); } Map> roomsByCustomer = batchActiveContractRoomIds(customerIds); Set allRoomIds = roomsByCustomer.values().stream() .flatMap(Set::stream).collect(Collectors.toCollection(LinkedHashSet::new)); Map> devicesByRoom = mapDevicesByRoom(allRoomIds, deviceType); Map> result = new LinkedHashMap<>(); for (Integer customerId : customerIds) { Set roomIds = roomsByCustomer.getOrDefault(customerId, Collections.emptySet()); Set deviceIds = new LinkedHashSet<>(); for (Integer roomId : roomIds) { deviceIds.addAll(devicesByRoom.getOrDefault(roomId, Collections.emptySet())); } result.put(customerId, new ArrayList<>(deviceIds)); } return result; } private Map> batchActiveContractRoomIds(List customerIds) { List contracts = ywContractMapper.selectList(new QueryWrapper().lambda() .in(YwContract::getRenterId, customerIds) .eq(YwContract::getIsdeleted, Constants.ZERO)); Map> activeByCustomer = contracts.stream() .filter(this::isActiveContract) .collect(Collectors.groupingBy(YwContract::getRenterId)); List contractIds = activeByCustomer.values().stream() .flatMap(List::stream).map(YwContract::getId).distinct().collect(Collectors.toList()); Map> roomsByContract = loadContractRoomMap(contractIds); Map> roomsByCustomer = new LinkedHashMap<>(); for (Integer customerId : customerIds) { Set 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> loadContractRoomMap(List contractIds) { if (CollectionUtils.isEmpty(contractIds)) { return Collections.emptyMap(); } return ywContractRoomMapper.selectList(new QueryWrapper().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> mapDevicesByRoom(Set roomIds, int deviceType) { if (CollectionUtils.isEmpty(roomIds)) { return Collections.emptyMap(); } List roomIdList = new ArrayList<>(roomIds); Map> result = new HashMap<>(); List relRooms = ywElectricalRoomMapper.selectList(new QueryWrapper().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 byRoom = ywConditionerMapper.selectList(new QueryWrapper().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 listActiveContracts(Integer customerId) { return ywContractMapper.selectList(new QueryWrapper().lambda() .eq(YwContract::getRenterId, customerId) .eq(YwContract::getIsdeleted, Constants.ZERO)) .stream().filter(this::isActiveContract).collect(Collectors.toList()); } private boolean isActiveContract(YwContract contract) { 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 && Utils.Date.getEnd(contract.getEndDate()).getTime() >= now; } private List listContractRoomIds(Integer contractId) { return ywContractRoomMapper.selectList(new QueryWrapper().lambda() .eq(YwContractRoom::getContractId, contractId) .eq(YwContractRoom::getType, Constants.ZERO) .eq(YwContractRoom::getIsdeleted, Constants.ZERO)) .stream().map(YwContractRoom::getRoomId).filter(Objects::nonNull).distinct() .collect(Collectors.toList()); } private Set resolveElectricalIdsFromRooms(List roomIds) { if (CollectionUtils.isEmpty(roomIds)) { return Collections.emptySet(); } return ywElectricalRoomMapper.selectList(new QueryWrapper().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 resolveConditionerIdsFromRooms(List roomIds) { if (CollectionUtils.isEmpty(roomIds)) { return Collections.emptySet(); } Set conditionerIds = new LinkedHashSet<>(); List acRooms = ywElectricalRoomMapper.selectList(new QueryWrapper().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); if (conditionerIds.isEmpty()) { ywConditionerMapper.selectList(new QueryWrapper().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 roomIds, LoginUserInfo user) { Set electricalIds = resolveElectricalIdsFromRooms(roomIds); if (electricalIds.isEmpty()) { return; } Set boundOthers = listBoundElectricalIdsExcept(contract.getRenterId()); Date now = new Date(); for (Integer eid : electricalIds) { if (boundOthers.contains(eid)) { log.warn("skip electrical {} already bound to other customer", eid); continue; } YwCustomerElectrical exist = ywCustomerElectricalMapper.selectOne(new QueryWrapper().lambda() .eq(YwCustomerElectrical::getCustomerId, contract.getRenterId()) .eq(YwCustomerElectrical::getElectricalId, eid) .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO) .last("limit 1")); if (exist != 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); exist.setEditor(user != null ? user.getId() : null); ywCustomerElectricalMapper.updateById(exist); } continue; } YwCustomerElectrical rel = new YwCustomerElectrical(); rel.setCreator(user != null ? user.getId() : null); rel.setCreateDate(now); rel.setEditor(user != null ? user.getId() : null); rel.setEditDate(now); rel.setIsdeleted(Constants.ZERO); rel.setCustomerId(contract.getRenterId()); rel.setElectricalId(eid); rel.setBindSource(BIND_SOURCE_CONTRACT); rel.setContractId(contract.getId()); ywCustomerElectricalMapper.insert(rel); } } private void bindConditionersMerged(Integer customerId, List roomIds, LoginUserInfo user) { Set conditionerIds = resolveConditionerIdsFromRooms(roomIds); if (conditionerIds.isEmpty()) { softDeleteAllConditionerRels(customerId, user); return; } YwCustomerGsConfigDTO dto = new YwCustomerGsConfigDTO(); dto.setCustomerId(customerId); dto.setIsPwr(Constants.ONE); dto.setIsRestStop(Constants.ZERO); dto.setGsBz("合同自动关联"); dto.setStopMoney(BigDecimal.ZERO); List items = new ArrayList<>(); for (Integer cid : conditionerIds) { YwCustomerGsConfigDTO.ConditionerItem item = new YwCustomerGsConfigDTO.ConditionerItem(); item.setConditionerId(cid); item.setDevRatio(100); items.add(item); } dto.setConditioners(items); try { ywCustomerRechargeBizService.saveCustomerGsConfig(dto, user); } catch (BusinessException e) { 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().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().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 listBoundElectricalIdsExcept(Integer customerId) { List list = ywCustomerElectricalMapper.selectList(new QueryWrapper().lambda() .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO) .ne(customerId != null, YwCustomerElectrical::getCustomerId, customerId)); return list.stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet()); } private LoginUserInfo systemUser() { LoginUserInfo u = new LoginUserInfo(); u.setId(1); u.setRealname("system"); return u; } }