package com.doumee.service.business.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.doumee.core.annotation.excel.ExcelExporter; import com.doumee.core.conditoner.ConditionerUtil; import com.doumee.core.conditoner.model.request.AddMoneyRequest; import com.doumee.core.conditoner.model.request.CompanyGsManageRequest; import com.doumee.core.conditoner.model.request.LogQueryRequest; import com.doumee.core.conditoner.model.response.CompanyGsInfoResponse; import com.doumee.core.conditoner.model.response.ConditionerBaseResponse; import com.doumee.core.constants.ResponseStatus; import com.doumee.core.exception.BusinessException; import com.doumee.core.model.LoginUserInfo; import com.doumee.core.model.PageData; import com.doumee.core.model.PageWrap; import com.doumee.core.utils.Constants; import com.doumee.core.utils.Utils; import com.doumee.dao.business.*; import com.doumee.dao.business.dto.*; import com.doumee.dao.business.model.*; import com.doumee.service.business.ConditionerBizService; import com.doumee.service.business.YwCustomerRechargeBizService; import com.doumee.service.business.YwElectricalBizService; import com.github.yulichang.wrapper.MPJLambdaWrapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @Service @Slf4j public class YwCustomerRechargeBizServiceImpl implements YwCustomerRechargeBizService { private static final String ONLINE_TEXT = "在线"; @Autowired private YwCustomerMapper ywCustomerMapper; @Autowired private YwCustomerGsMapper ywCustomerGsMapper; @Autowired private YwCustomerElectricalMapper ywCustomerElectricalMapper; @Autowired private YwCustomerConditionerMapper ywCustomerConditionerMapper; @Autowired private YwElectricalMapper ywElectricalMapper; @Autowired private YwConditionerMapper ywConditionerMapper; @Autowired private YwElectricalChargeMapper ywElectricalChargeMapper; @Autowired private YwElectricalActionsMapper ywElectricalActionsMapper; @Autowired private YwElectricalBizService ywElectricalBizService; @Autowired private ConditionerBizService conditionerBizService; @Override public PageData findMerchantPage(PageWrap pageWrap) { if (pageWrap == null) { pageWrap = new PageWrap<>(); } YwCustomerRechargeQueryDTO query = pageWrap.getModel() != null ? pageWrap.getModel() : new YwCustomerRechargeQueryDTO(); boolean hasDeviceFilter = query.getElectricalStatusFilter() != null || query.getConditionerStatusFilter() != null; if (hasDeviceFilter) { List all = ywCustomerMapper.selectJoinList(YwCustomer.class, buildMerchantCustomerWrapper(query)); List enriched = enrichMerchantList(all); List filtered = enriched.stream() .filter(vo -> matchDeviceFilter(vo, query)) .collect(Collectors.toList()); return manualPage(filtered, pageWrap.getPage(), pageWrap.getCapacity()); } IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); IPage result = ywCustomerMapper.selectJoinPage(page, YwCustomer.class, buildMerchantCustomerWrapper(query)); List list = enrichMerchantList(result.getRecords()); PageData data = new PageData<>(); data.setRecords(list); data.setTotal(result.getTotal()); data.setPage(result.getCurrent()); data.setCapacity(result.getSize()); return data; } private MPJLambdaWrapper buildMerchantCustomerWrapper(YwCustomerRechargeQueryDTO query) { return new MPJLambdaWrapper() .selectAll(YwCustomer.class) .selectAs(Member::getName, YwCustomer::getMemberName) .selectAs(Member::getPhone, YwCustomer::getMemberPhone) .leftJoin(Member.class, Member::getId, YwCustomer::getMemberId) .eq(YwCustomer::getIsdeleted, Constants.ZERO) .like(StringUtils.isNotBlank(query.getNameKeyword()), YwCustomer::getName, query.getNameKeyword()) .orderByDesc(YwCustomer::getCreateDate); } private PageData manualPage(List list, long page, long capacity) { int p = (int) Math.max(page, 1); int size = (int) Math.max(capacity, 1); int from = (p - 1) * size; int to = Math.min(from + size, list.size()); PageData data = new PageData<>(); data.setTotal(list.size()); data.setPage(p); data.setCapacity(size); data.setRecords(from >= list.size() ? Collections.emptyList() : list.subList(from, to)); return data; } private boolean matchDeviceFilter(YwCustomerRechargeMerchantVO vo, YwCustomerRechargeQueryDTO query) { if (query.getElectricalStatusFilter() != null && !matchStatusFilter( query.getElectricalStatusFilter(), vo.getElectricalCount(), vo.getElectricalOnlineAll(), vo.getElectricalHasOffline())) { return false; } if (query.getConditionerStatusFilter() != null && !matchStatusFilter( query.getConditionerStatusFilter(), vo.getConditionerCount(), vo.getConditionerOnlineAll(), vo.getConditionerHasOffline())) { return false; } return true; } private boolean matchStatusFilter(Integer filter, Integer count, Boolean allOnline, Boolean hasOffline) { int c = count != null ? count : 0; if (filter == 3) { return c == 0; } if (c == 0) { return false; } if (filter == 1) { return Boolean.TRUE.equals(allOnline); } if (filter == 2) { return Boolean.TRUE.equals(hasOffline); } return true; } private List enrichMerchantList(List customers) { if (CollectionUtils.isEmpty(customers)) { return Collections.emptyList(); } List customerIds = customers.stream().map(YwCustomer::getId).collect(Collectors.toList()); Map gsMap = loadGsMap(customerIds); List relE = loadCustomerElectricalRels(customerIds); Map> customerElectricalIds = relE.stream() .collect(Collectors.groupingBy(YwCustomerElectrical::getCustomerId, Collectors.mapping(YwCustomerElectrical::getElectricalId, Collectors.toList()))); List relC = loadCustomerConditionerRels(customerIds); Map> customerConditionerIds = relC.stream() .collect(Collectors.groupingBy(YwCustomerConditioner::getCustomerId, Collectors.mapping(YwCustomerConditioner::getConditionerId, Collectors.toList()))); Set allElectricalIds = relE.stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet()); Map electricalMap = loadElectricalMap(allElectricalIds); Set allConditionerIds = relC.stream().map(YwCustomerConditioner::getConditionerId).collect(Collectors.toSet()); Map conditionerMap = loadConditionerMap(allConditionerIds); List list = new ArrayList<>(); for (YwCustomer c : customers) { YwCustomerRechargeMerchantVO vo = new YwCustomerRechargeMerchantVO(); vo.setId(c.getId()); vo.setType(c.getType()); vo.setName(c.getName()); vo.setPhone(c.getPhone()); vo.setCreateDate(c.getCreateDate()); vo.setMemberName(c.getMemberName()); vo.setMemberPhone(StringUtils.defaultIfBlank(c.getMemberPhone(), c.getPhone())); List eIds = customerElectricalIds.getOrDefault(c.getId(), Collections.emptyList()); vo.setElectricalCount(eIds.size()); if (eIds.isEmpty()) { vo.setElectricalBalances(Collections.emptyList()); vo.setElectricalOnlineAll(false); vo.setElectricalHasOffline(false); } else { List balanceItems = new ArrayList<>(); boolean allOnline = true; boolean hasOffline = false; int index = 0; for (Integer eid : eIds) { YwElectrical e = electricalMap.get(eid); if (e == null) continue; YwCustomerElectricalBalanceItem item = new YwCustomerElectricalBalanceItem(); index++; item.setName(StringUtils.isNotBlank(e.getName()) ? e.getName() : ("电表" + index)); item.setAddress(StringUtils.isNotBlank(e.getAddress()) ? e.getAddress() : "-"); item.setBalance(e.getBalance() != null ? e.getBalance() : BigDecimal.ZERO); balanceItems.add(item); if (!Objects.equals(e.getOnline(), Constants.ONE)) { allOnline = false; hasOffline = true; } } vo.setElectricalBalances(balanceItems); vo.setElectricalOnlineAll(allOnline && !balanceItems.isEmpty()); vo.setElectricalHasOffline(hasOffline); } List cIds = customerConditionerIds.getOrDefault(c.getId(), Collections.emptyList()); vo.setConditionerCount(cIds.size()); if (cIds.isEmpty()) { vo.setConditionerOnlineAll(false); vo.setConditionerHasOffline(false); } else { boolean allOnline = true; boolean hasOffline = false; for (Integer cid : cIds) { YwConditioner cond = conditionerMap.get(cid); if (cond == null) continue; if (!ONLINE_TEXT.equals(cond.getOnline())) { allOnline = false; hasOffline = true; } } vo.setConditionerOnlineAll(allOnline); vo.setConditionerHasOffline(hasOffline); } YwCustomerGs gs = gsMap.get(c.getId()); if (gs != null) { vo.setAcBalance(gs.getLeftMoney()); vo.setAcBalanceSyncDate(gs.getSyncDate()); } list.add(vo); } return list; } private Map loadGsMap(List customerIds) { if (CollectionUtils.isEmpty(customerIds)) { return Collections.emptyMap(); } try { return ywCustomerGsMapper.selectList(new QueryWrapper().lambda() .select(YwCustomerGs::getId, YwCustomerGs::getCustomerId, YwCustomerGs::getLeftMoney, YwCustomerGs::getSyncDate, YwCustomerGs::getPlatformGsId) .eq(YwCustomerGs::getIsdeleted, Constants.ZERO) .in(YwCustomerGs::getCustomerId, customerIds)) .stream().collect(Collectors.toMap(YwCustomerGs::getCustomerId, g -> g, (a, b) -> a)); } catch (Exception e) { log.warn("load yw_customer_gs failed, skip gs stats: {}", e.getMessage()); return Collections.emptyMap(); } } private List loadCustomerElectricalRels(List customerIds) { if (CollectionUtils.isEmpty(customerIds)) { return Collections.emptyList(); } try { return ywCustomerElectricalMapper.selectList(new QueryWrapper().lambda() .select(YwCustomerElectrical::getCustomerId, YwCustomerElectrical::getElectricalId) .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO) .in(YwCustomerElectrical::getCustomerId, customerIds)); } catch (Exception e) { log.warn("load yw_customer_electrical failed, skip electrical stats: {}", e.getMessage()); return Collections.emptyList(); } } private List loadCustomerConditionerRels(List customerIds) { if (CollectionUtils.isEmpty(customerIds)) { return Collections.emptyList(); } try { return ywCustomerConditionerMapper.selectList(new QueryWrapper().lambda() .select(YwCustomerConditioner::getCustomerId, YwCustomerConditioner::getConditionerId) .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO) .in(YwCustomerConditioner::getCustomerId, customerIds)); } catch (Exception e) { log.warn("load yw_customer_conditioner failed, skip conditioner stats: {}", e.getMessage()); return Collections.emptyList(); } } private Map loadElectricalMap(Set electricalIds) { if (CollectionUtils.isEmpty(electricalIds)) { return Collections.emptyMap(); } try { return ywElectricalMapper.selectList(new QueryWrapper().lambda() .select(YwElectrical::getId, YwElectrical::getName, YwElectrical::getAddress, YwElectrical::getBalance, YwElectrical::getOnline, YwElectrical::getIsdeleted) .in(YwElectrical::getId, electricalIds) .eq(YwElectrical::getIsdeleted, Constants.ZERO)) .stream().collect(Collectors.toMap(YwElectrical::getId, e -> e, (a, b) -> a)); } catch (Exception e) { log.warn("load electrical for merchant page failed: {}", e.getMessage()); return Collections.emptyMap(); } } private Map loadConditionerMap(Set conditionerIds) { if (CollectionUtils.isEmpty(conditionerIds)) { return Collections.emptyMap(); } try { return ywConditionerMapper.selectList(new QueryWrapper().lambda() .select(YwConditioner::getId, YwConditioner::getOnline, YwConditioner::getIsdeleted) .in(YwConditioner::getId, conditionerIds) .eq(YwConditioner::getIsdeleted, Constants.ZERO)) .stream().collect(Collectors.toMap(YwConditioner::getId, c -> c, (a, b) -> a)); } catch (Exception e) { log.warn("load conditioner for merchant page failed: {}", e.getMessage()); return Collections.emptyMap(); } } @Override public YwCustomerRechargeDetailVO getDetail(Integer customerId) { YwCustomer customer = requireCustomer(customerId); YwCustomerRechargeDetailVO vo = new YwCustomerRechargeDetailVO(); vo.setCustomerId(customer.getId()); vo.setCustomerName(customer.getName()); vo.setPhone(customer.getPhone()); vo.setGsConfig(getCustomerGsConfig(customerId)); vo.setElectricalList(loadCustomerElectricalList(customerId)); vo.setConditionerList(loadCustomerConditionerList(customerId)); return vo; } @Override public PageData listCustomerElectrical(PageWrap pageWrap, Integer customerId) { requireCustomer(customerId); List ids = listBoundElectricalIds(customerId); if (ids.isEmpty()) { return emptyPage(pageWrap); } return pageElectricalByIds(pageWrap, ids); } @Override public PageData pageSelectableElectrical(PageWrap pageWrap, Integer customerId) { requireCustomer(customerId); Set excluded = listAllBoundElectricalIds(); IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); YwElectrical model = pageWrap.getModel(); QueryWrapper qw = new QueryWrapper<>(); qw.lambda() .eq(YwElectrical::getIsdeleted, Constants.ZERO) .notIn(!excluded.isEmpty(), YwElectrical::getId, excluded) .and(model != null && StringUtils.isNotBlank(model.getName()), w -> w .like(YwElectrical::getName, model.getName()) .or().like(YwElectrical::getAddress, model.getName())) .orderByDesc(YwElectrical::getCreateDate); IPage result = ywElectricalMapper.selectPage(page, qw); ywElectricalBizService.enrichList(result.getRecords()); return PageData.from(result); } @Override @Transactional(rollbackFor = Exception.class) public void saveCustomerElectrical(YwCustomerElectricalSaveDTO dto, LoginUserInfo user) { requireCustomer(dto.getCustomerId()); if (CollectionUtils.isEmpty(dto.getElectricalIds())) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请选择电表"); } Set excluded = listAllBoundElectricalIdsExcept(dto.getCustomerId()); for (Integer eid : dto.getElectricalIds()) { if (excluded.contains(eid)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "电表已被其他商户绑定:" + eid); } YwCustomerElectrical exist = ywCustomerElectricalMapper.selectOne(new QueryWrapper().lambda() .eq(YwCustomerElectrical::getCustomerId, dto.getCustomerId()) .eq(YwCustomerElectrical::getElectricalId, eid) .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO) .last("limit 1")); if (exist != null) { continue; } YwCustomerElectrical rel = new YwCustomerElectrical(); rel.setCreator(user.getId()); rel.setCreateDate(new Date()); rel.setEditor(user.getId()); rel.setEditDate(new Date()); rel.setIsdeleted(Constants.ZERO); rel.setCustomerId(dto.getCustomerId()); rel.setElectricalId(eid); ywCustomerElectricalMapper.insert(rel); } } @Override @Transactional(rollbackFor = Exception.class) public void removeCustomerElectrical(Integer customerId, Integer electricalId, LoginUserInfo user) { ywCustomerElectricalMapper.update(null, new UpdateWrapper().lambda() .set(YwCustomerElectrical::getIsdeleted, Constants.ONE) .set(YwCustomerElectrical::getEditDate, new Date()) .set(YwCustomerElectrical::getEditor, user.getId()) .eq(YwCustomerElectrical::getCustomerId, customerId) .eq(YwCustomerElectrical::getElectricalId, electricalId) .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)); } @Override public PageData listCustomerConditioner(PageWrap pageWrap, Integer customerId) { requireCustomer(customerId); List list = loadCustomerConditionerList(customerId); if (CollectionUtils.isEmpty(list)) { return emptyPage(pageWrap); } int p = (int) Math.max(pageWrap.getPage(), 1); int size = (int) Math.max(pageWrap.getCapacity(), 1); int from = (p - 1) * size; int to = Math.min(from + size, list.size()); PageData data = new PageData<>(); data.setTotal(list.size()); data.setPage(p); data.setCapacity(size); data.setRecords(from >= list.size() ? Collections.emptyList() : list.subList(from, to)); return data; } @Override public YwCustomerGs getCustomerGsConfig(Integer customerId) { try { return ywCustomerGsMapper.selectOne(new QueryWrapper().lambda() .eq(YwCustomerGs::getCustomerId, customerId) .eq(YwCustomerGs::getIsdeleted, Constants.ZERO) .last("limit 1")); } catch (Exception e) { log.warn("load yw_customer_gs failed, retry without stop_money: {}", e.getMessage()); return ywCustomerGsMapper.selectOne(new QueryWrapper().lambda() .select(YwCustomerGs::getId, YwCustomerGs::getCustomerId, YwCustomerGs::getPlatformGsId, YwCustomerGs::getIsPwr, YwCustomerGs::getIsRestStop, YwCustomerGs::getGsBz, YwCustomerGs::getLeftMoney, YwCustomerGs::getSyncDate, YwCustomerGs::getCreator, YwCustomerGs::getCreateDate, YwCustomerGs::getEditor, YwCustomerGs::getEditDate, YwCustomerGs::getIsdeleted) .eq(YwCustomerGs::getCustomerId, customerId) .eq(YwCustomerGs::getIsdeleted, Constants.ZERO) .last("limit 1")); } } @Override @Transactional(rollbackFor = Exception.class) public void saveCustomerGsConfig(YwCustomerGsConfigDTO dto, LoginUserInfo user) { YwCustomer customer = requireCustomer(dto.getCustomerId()); validateGsConfigRequired(dto); conditionerBizService.ensureLogin(); List conditionerIds = dto.getConditioners().stream() .map(YwCustomerGsConfigDTO.ConditionerItem::getConditionerId) .filter(Objects::nonNull) .collect(Collectors.toList()); List conditioners = ywConditionerMapper.selectBatchIds(conditionerIds); Map condMap = conditioners.stream() .filter(c -> !Objects.equals(c.getIsdeleted(), Constants.ONE)) .collect(Collectors.toMap(YwConditioner::getId, c -> c, (a, b) -> a)); List liDev = new ArrayList<>(); Map dDev = new LinkedHashMap<>(); for (YwCustomerGsConfigDTO.ConditionerItem item : dto.getConditioners()) { YwConditioner cond = condMap.get(item.getConditionerId()); if (cond == null || cond.getPlatformDevId() == null) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "内机缺少平台设备 ID"); } liDev.add(cond.getPlatformDevId()); int ratio = item.getDevRatio() != null ? item.getDevRatio() : 100; dDev.put(String.valueOf(cond.getPlatformDevId()), ratio); } YwCustomerGs gs = getCustomerGsConfig(dto.getCustomerId()); if (gs == null) { gs = new YwCustomerGs(); gs.setCreator(user.getId()); gs.setCreateDate(new Date()); gs.setIsdeleted(Constants.ZERO); gs.setCustomerId(dto.getCustomerId()); } gs.setEditor(user.getId()); gs.setEditDate(new Date()); gs.setIsPwr(dto.getIsPwr()); gs.setIsRestStop(dto.getIsRestStop()); gs.setGsBz(StringUtils.defaultString(dto.getGsBz())); gs.setStopMoney(dto.getStopMoney()); if (StringUtils.isBlank(customer.getName())) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "客户名称不能为空"); } if (liDev.isEmpty()) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "关联内机平台设备 ID 无效"); } CompanyGsManageRequest companyReq = new CompanyGsManageRequest(); companyReq.fillSessionDefaults(); companyReq.setGs_name(customer.getName().trim()); companyReq.setIs_pwr(gs.getIsPwr()); companyReq.setIs_rest_stop(gs.getIsRestStop()); companyReq.setGs_bz(gs.getGsBz()); companyReq.setStop_money(gs.getStopMoney()); companyReq.setLi_dev(liDev); companyReq.setD_dev(dDev); if (gs.getPlatformGsId() == null) { ConditionerBaseResponse addResp = ConditionerUtil.addGs(companyReq); if (addResp == null || !addResp.isSuccess()) { throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(addResp, "addGs 失败")); } gs.setPlatformGsId(parseAddGsId(addResp.getData())); if (gs.getPlatformGsId() == null) { throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), "addGs 未返回公司 ID"); } } CompanyGsManageRequest changeReq = new CompanyGsManageRequest(); changeReq.fillSessionDefaults(); changeReq.setId(gs.getPlatformGsId()); changeReq.setGs_name(companyReq.getGs_name()); changeReq.setIs_pwr(companyReq.getIs_pwr()); changeReq.setIs_rest_stop(companyReq.getIs_rest_stop()); changeReq.setGs_bz(companyReq.getGs_bz()); changeReq.setStop_money(gs.getStopMoney()); changeReq.setLi_dev(liDev); changeReq.setD_dev(dDev); if (gs.getLeftMoney() != null) { changeReq.setLeft_money(gs.getLeftMoney()); } ConditionerBaseResponse changeResp = ConditionerUtil.changeGs(changeReq); if (changeResp == null || !changeResp.isSuccess()) { throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(changeResp, "changeGs 失败")); } refreshGsLeftMoney(gs); if (gs.getId() == null) { try { ywCustomerGsMapper.insert(gs); } catch (Exception e) { if (gs.getStopMoney() != null) { log.warn("insert yw_customer_gs with stop_money failed, retry without stop_money: {}", e.getMessage()); gs.setStopMoney(null); ywCustomerGsMapper.insert(gs); } else { throw e; } } } else { try { ywCustomerGsMapper.updateById(gs); } catch (Exception e) { if (gs.getStopMoney() != null) { log.warn("update yw_customer_gs with stop_money failed, retry without stop_money: {}", e.getMessage()); BigDecimal stopMoney = gs.getStopMoney(); gs.setStopMoney(null); ywCustomerGsMapper.updateById(gs); gs.setStopMoney(stopMoney); } else { throw e; } } } saveCustomerConditionerRels(dto, user); } /** * 关联内机 upsert:表上有 uk(customer_id, conditioner_id),不能软删后重复 insert。 */ private void saveCustomerConditionerRels(YwCustomerGsConfigDTO dto, LoginUserInfo user) { List existingRels = ywCustomerConditionerMapper.selectList( new QueryWrapper().lambda() .eq(YwCustomerConditioner::getCustomerId, dto.getCustomerId())); Map relByCondId = existingRels.stream() .collect(Collectors.toMap(YwCustomerConditioner::getConditionerId, r -> r, (a, b) -> a)); Set targetIds = dto.getConditioners().stream() .map(YwCustomerGsConfigDTO.ConditionerItem::getConditionerId) .filter(Objects::nonNull) .collect(Collectors.toSet()); Date now = new Date(); for (YwCustomerConditioner rel : existingRels) { if (!targetIds.contains(rel.getConditionerId()) && Objects.equals(rel.getIsdeleted(), Constants.ZERO)) { ywCustomerConditionerMapper.update(null, new UpdateWrapper().lambda() .set(YwCustomerConditioner::getIsdeleted, Constants.ONE) .set(YwCustomerConditioner::getEditDate, now) .set(YwCustomerConditioner::getEditor, user.getId()) .eq(YwCustomerConditioner::getId, rel.getId())); } } for (YwCustomerGsConfigDTO.ConditionerItem item : dto.getConditioners()) { if (item.getConditionerId() == null) { continue; } int ratio = item.getDevRatio() != null ? item.getDevRatio() : 100; YwCustomerConditioner rel = relByCondId.get(item.getConditionerId()); if (rel != null) { rel.setIsdeleted(Constants.ZERO); rel.setDevRatio(ratio); rel.setEditor(user.getId()); rel.setEditDate(now); ywCustomerConditionerMapper.updateById(rel); } else { YwCustomerConditioner created = new YwCustomerConditioner(); created.setCreator(user.getId()); created.setCreateDate(now); created.setEditor(user.getId()); created.setEditDate(now); created.setIsdeleted(Constants.ZERO); created.setCustomerId(dto.getCustomerId()); created.setConditionerId(item.getConditionerId()); created.setDevRatio(ratio); ywCustomerConditionerMapper.insert(created); relByCondId.put(item.getConditionerId(), created); } } } @Override @Transactional(rollbackFor = Exception.class) public String rechargeElectrical(YwCustomerRechargeElectricalDTO dto, LoginUserInfo user) { requireCustomer(dto.getCustomerId()); assertElectricalBound(dto.getCustomerId(), dto.getElectricalId()); YwElectricalOperateDTO op = new YwElectricalOperateDTO(); op.setElectricalId(dto.getElectricalId()); op.setAction("recharge"); op.setMoney(dto.getMoney()); op.setRemark(dto.getRemark()); op.setCustomerId(dto.getCustomerId()); return ywElectricalBizService.operate(op, user); } @Override @Transactional(rollbackFor = Exception.class) public String resetElectricalAccount(YwCustomerRechargeElectricalDTO dto, LoginUserInfo user) { requireCustomer(dto.getCustomerId()); assertElectricalBound(dto.getCustomerId(), dto.getElectricalId()); String action = StringUtils.defaultIfBlank(dto.getResetAction(), "resetPrepay"); YwElectricalOperateDTO op = new YwElectricalOperateDTO(); op.setElectricalId(dto.getElectricalId()); op.setAction(action); op.setCustomerId(dto.getCustomerId()); return ywElectricalBizService.operate(op, user); } @Override public Map getElectricalRemoteInfo(Integer electricalId) { return ywElectricalBizService.getRemoteInfo(electricalId); } @Override public Map readMeterAndRefresh(Integer customerId, Integer electricalId, LoginUserInfo user) { assertElectricalBound(customerId, electricalId); YwElectricalOperateDTO op = new YwElectricalOperateDTO(); op.setElectricalId(electricalId); op.setAction("readMeter"); op.setCustomerId(customerId); String msg = ywElectricalBizService.operate(op, user); Map info = ywElectricalBizService.getRemoteInfo(electricalId); info.put("message", msg); return info; } @Override public Map getConditionerRechargeInfo(Integer customerId) { YwCustomerGs gs = requireGsConfig(customerId); conditionerBizService.ensureLogin(); refreshGsLeftMoney(gs); ywCustomerGsMapper.updateById(gs); Map map = new LinkedHashMap<>(); map.put("gsConfig", gs); map.put("customerName", requireCustomer(customerId).getName()); CompanyGsManageRequest req = new CompanyGsManageRequest(); req.fillSessionDefaults(); req.setId(gs.getPlatformGsId()); ConditionerBaseResponse> resp = ConditionerUtil.getGs(req); if (resp != null && resp.isSuccess() && !CollectionUtils.isEmpty(resp.getData())) { CompanyGsInfoResponse info = resp.getData().get(0); map.put("platformInfo", info); } return map; } @Override public String rechargeConditioner(YwCustomerRechargeConditionerDTO dto, LoginUserInfo user) { YwCustomerGs gs = requireGsConfig(dto.getCustomerId()); if (dto.getMoney() == null || dto.getMoney().compareTo(BigDecimal.ZERO) <= 0) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "充值金额须大于 0"); } conditionerBizService.ensureLogin(); AddMoneyRequest req = new AddMoneyRequest(); req.fillSessionDefaults(); req.setId(gs.getPlatformGsId()); req.setCz_money(dto.getMoney().toPlainString()); ConditionerBaseResponse resp = ConditionerUtil.addMoney(req); YwElectricalCharge charge = buildConditionerCharge(dto, gs, user); if (resp != null && resp.isSuccess()) { refreshGsLeftMoney(gs); ywCustomerGsMapper.updateById(gs); charge.setStatus(Constants.ONE); charge.setStatusInfo("充值成功"); charge.setBalanceAfter(gs.getLeftMoney()); ywElectricalChargeMapper.insert(charge); return "充值成功"; } charge.setStatus(Constants.TWO); charge.setStatusInfo(apiMsg(resp, "充值失败")); ywElectricalChargeMapper.insert(charge); throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), charge.getStatusInfo()); } @Override @Transactional(rollbackFor = Exception.class) public String cleanConditionerAccount(Integer customerId, LoginUserInfo user) { YwCustomerGs gs = requireGsConfig(customerId); conditionerBizService.ensureLogin(); CompanyGsManageRequest req = new CompanyGsManageRequest(); req.fillSessionDefaults(); req.setId(gs.getPlatformGsId()); ConditionerBaseResponse resp = ConditionerUtil.cleanMoney(req); if (resp == null || !resp.isSuccess()) { throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "清零失败")); } refreshGsLeftMoney(gs); gs.setEditor(user.getId()); gs.setEditDate(new Date()); ywCustomerGsMapper.updateById(gs); return "清零成功"; } @Override public PageData findRechargeRecordPage(PageWrap pageWrap) { Utils.MP.blankToNull(pageWrap.getModel()); YwCustomerRechargeRecordQueryDTO query = pageWrap.getModel() != null ? pageWrap.getModel() : new YwCustomerRechargeRecordQueryDTO(); IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); MPJLambdaWrapper wrapper = new MPJLambdaWrapper() .selectAll(YwElectricalCharge.class) .selectAs(YwCustomer::getName, YwCustomerRechargeRecordVO::getCustomerName) .leftJoin(YwCustomer.class, YwCustomer::getId, YwElectricalCharge::getCustomerId) .isNotNull(YwElectricalCharge::getCustomerId) .eq(YwElectricalCharge::getIsdeleted, Constants.ZERO) .eq(query.getType() != null, YwElectricalCharge::getType, query.getType()) .eq(query.getStatus() != null, YwElectricalCharge::getStatus, query.getStatus()) .like(StringUtils.isNotBlank(query.getCustomerName()), YwCustomer::getName, query.getCustomerName()) .ge(query.getCreateTimeBegin() != null, YwElectricalCharge::getCreateDate, query.getCreateTimeBegin()) .le(query.getCreateTimeEnd() != null, YwElectricalCharge::getCreateDate, query.getCreateTimeEnd()) .orderByDesc(YwElectricalCharge::getCreateDate); IPage result = ywElectricalChargeMapper.selectJoinPage(page, YwCustomerRechargeRecordVO.class, wrapper); result.getRecords().forEach(this::fillRecordText); return PageData.from(result); } @Override @Transactional(rollbackFor = Exception.class) public String retryRecharge(Integer id, LoginUserInfo user) { YwElectricalCharge charge = requireCharge(id); if (!Objects.equals(charge.getStatus(), Constants.TWO)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅失败记录可再次提交"); } if (Objects.equals(charge.getType(), Constants.ZERO)) { YwCustomerRechargeElectricalDTO dto = new YwCustomerRechargeElectricalDTO(); dto.setCustomerId(charge.getCustomerId()); dto.setElectricalId(charge.getObjId()); dto.setMoney(charge.getMoney()); dto.setRemark(charge.getRemark()); return rechargeElectrical(dto, user); } if (Objects.equals(charge.getType(), Constants.ONE)) { YwCustomerRechargeConditionerDTO dto = new YwCustomerRechargeConditionerDTO(); dto.setCustomerId(charge.getCustomerId()); dto.setMoney(charge.getMoney()); dto.setRemark(charge.getRemark()); return rechargeConditioner(dto, user); } throw new BusinessException(ResponseStatus.BAD_REQUEST); } @Override @Transactional(rollbackFor = Exception.class) public String syncRechargeStatus(Integer id, LoginUserInfo user) { YwElectricalCharge charge = requireCharge(id); if (!Objects.equals(charge.getStatus(), Constants.ZERO)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅充值中记录可同步"); } if (Objects.equals(charge.getType(), Constants.ZERO)) { return syncElectricalChargeStatus(charge, user); } if (Objects.equals(charge.getType(), Constants.ONE)) { return syncConditionerChargeStatus(charge, user); } throw new BusinessException(ResponseStatus.BAD_REQUEST); } @Override public void exportRechargeRecord(PageWrap pageWrap, HttpServletResponse response) { pageWrap.setPage(1); pageWrap.setCapacity(Integer.MAX_VALUE); List records = findRechargeRecordPage(pageWrap).getRecords(); ExcelExporter.build(YwCustomerRechargeRecordVO.class).export(records, "商户充值记录", response); } private String syncElectricalChargeStatus(YwElectricalCharge charge, LoginUserInfo user) { return ywElectricalBizService.syncAsyncActionStatus(charge.getOprId()); } private String syncConditionerChargeStatus(YwElectricalCharge charge, LoginUserInfo user) { YwCustomerGs gs = requireGsConfig(charge.getCustomerId()); conditionerBizService.ensureLogin(); LogQueryRequest req = new LogQueryRequest(); req.fillSessionDefaults(); req.setPage(1); req.setPageSize(50); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); if (charge.getCreateDate() != null) { String day = sdf.format(charge.getCreateDate()); req.setStart_time(day); req.setEnd_time(day); } ConditionerBaseResponse> resp = ConditionerUtil.getCzLog(req); if (resp == null || !resp.isSuccess() || CollectionUtils.isEmpty(resp.getData())) { return "未匹配到平台充值日志,仍为充值中"; } for (Object row : resp.getData()) { JSONObject o = (JSONObject) JSON.toJSON(row); if (!matchCzLog(o, gs.getPlatformGsId(), charge)) { continue; } refreshGsLeftMoney(gs); ywCustomerGsMapper.updateById(gs); updateChargeStatus(charge.getId(), Constants.ONE, "充值成功", gs.getLeftMoney()); return "已同步为充值成功"; } return "未匹配到平台充值日志,仍为充值中"; } private boolean matchCzLog(JSONObject o, Integer gsId, YwElectricalCharge charge) { Integer logGsId = o.getInteger("gs_id"); if (logGsId == null) { logGsId = o.getInteger("id"); } if (!Objects.equals(logGsId, gsId)) { return false; } String money = o.getString("cz_money"); if (money == null) { money = o.getString("money"); } if (charge.getMoney() != null && money != null) { try { return charge.getMoney().compareTo(new BigDecimal(money)) == 0; } catch (NumberFormatException ignored) { } } return true; } private void updateChargeStatus(Integer id, int status, String statusInfo, BigDecimal balanceAfter) { UpdateWrapper uw = new UpdateWrapper<>(); uw.lambda() .set(YwElectricalCharge::getStatus, status) .set(YwElectricalCharge::getStatusInfo, statusInfo) .set(YwElectricalCharge::getStatusTime, new Date()) .set(YwElectricalCharge::getEditDate, new Date()) .eq(YwElectricalCharge::getId, id); if (balanceAfter != null) { uw.lambda().set(YwElectricalCharge::getBalanceAfter, balanceAfter); } ywElectricalChargeMapper.update(null, uw); } private YwElectricalCharge buildConditionerCharge(YwCustomerRechargeConditionerDTO dto, YwCustomerGs gs, LoginUserInfo user) { YwCustomer customer = requireCustomer(dto.getCustomerId()); YwElectricalCharge charge = new YwElectricalCharge(); charge.setCreator(user.getId()); charge.setCreateDate(new Date()); charge.setEditor(user.getId()); charge.setEditDate(new Date()); charge.setIsdeleted(Constants.ZERO); charge.setType(Constants.ONE); charge.setCustomerId(dto.getCustomerId()); charge.setObjId(gs.getId()); charge.setName(customer.getName()); charge.setMoney(dto.getMoney()); charge.setRemark(dto.getRemark()); charge.setBanlance(gs.getLeftMoney()); charge.setStatus(Constants.ZERO); charge.setStatusTime(new Date()); charge.setStatusInfo("充值中"); charge.setDeviceInfo("GS-" + gs.getPlatformGsId() + " " + customer.getName()); return charge; } private void fillRecordText(YwCustomerRechargeRecordVO vo) { if (StringUtils.isBlank(vo.getDeviceInfo())) { if (StringUtils.isNotBlank(vo.getAddress()) || StringUtils.isNotBlank(vo.getName())) { vo.setDeviceInfo(StringUtils.defaultString(vo.getAddress()) + " " + StringUtils.defaultString(vo.getName())); } } vo.setTypeText(Objects.equals(vo.getType(), Constants.ONE) ? "空调" : "电表"); if (Objects.equals(vo.getStatus(), Constants.ZERO)) { vo.setStatusText("充值中"); } else if (Objects.equals(vo.getStatus(), Constants.ONE)) { vo.setStatusText("充值成功"); } else if (Objects.equals(vo.getStatus(), Constants.TWO)) { vo.setStatusText("充值失败"); } } private YwElectricalCharge requireCharge(Integer id) { YwElectricalCharge charge = ywElectricalChargeMapper.selectById(id); if (charge == null || Objects.equals(charge.getIsdeleted(), Constants.ONE) || charge.getCustomerId() == null) { throw new BusinessException(ResponseStatus.DATA_EMPTY); } return charge; } private void refreshGsLeftMoney(YwCustomerGs gs) { if (gs.getPlatformGsId() == null) { return; } CompanyGsManageRequest req = new CompanyGsManageRequest(); req.fillSessionDefaults(); req.setId(gs.getPlatformGsId()); ConditionerBaseResponse> resp = ConditionerUtil.getGs(req); if (resp == null || !resp.isSuccess() || CollectionUtils.isEmpty(resp.getData())) { return; } CompanyGsInfoResponse info = resp.getData().stream() .filter(i -> Objects.equals(i.getId(), gs.getPlatformGsId())) .findFirst().orElse(resp.getData().get(0)); gs.setLeftMoney(toBigDecimal(info.getLeft_money())); gs.setSyncDate(new Date()); } private Integer parseAddGsId(Object data) { if (data == null) { return null; } if (data instanceof Number) { return ((Number) data).intValue(); } JSONObject obj = (JSONObject) JSON.toJSON(data); if (obj.containsKey("id")) { return obj.getInteger("id"); } return null; } private BigDecimal toBigDecimal(Object val) { if (val == null) { return null; } if (val instanceof BigDecimal) { return (BigDecimal) val; } if (val instanceof Number) { return BigDecimal.valueOf(((Number) val).doubleValue()); } try { return new BigDecimal(String.valueOf(val)); } catch (NumberFormatException e) { return null; } } private void validateGsConfigRequired(YwCustomerGsConfigDTO dto) { if (dto.getStopMoney() == null) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "欠费额度不能为空"); } if (dto.getStopMoney().compareTo(BigDecimal.ZERO) < 0) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "欠费额度不能小于0"); } if (dto.getIsPwr() == null) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "计费开关不能为空"); } if (dto.getIsRestStop() == null) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "是否停机不能为空"); } if (CollectionUtils.isEmpty(dto.getConditioners())) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请至少关联一台空调内机"); } } private String apiMsg(ConditionerBaseResponse resp, String def) { return resp != null && StringUtils.isNotBlank(resp.getMessage()) ? resp.getMessage() : def; } private YwCustomer requireCustomer(Integer customerId) { YwCustomer c = ywCustomerMapper.selectById(customerId); if (c == null || Objects.equals(c.getIsdeleted(), Constants.ONE)) { throw new BusinessException(ResponseStatus.DATA_EMPTY); } return c; } private YwCustomerGs requireGsConfig(Integer customerId) { YwCustomerGs gs = getCustomerGsConfig(customerId); if (gs == null || gs.getPlatformGsId() == null) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请先配置并保存空调关联"); } return gs; } private void assertElectricalBound(Integer customerId, Integer electricalId) { Long cnt = ywCustomerElectricalMapper.selectCount(new QueryWrapper().lambda() .eq(YwCustomerElectrical::getCustomerId, customerId) .eq(YwCustomerElectrical::getElectricalId, electricalId) .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)); if (cnt == null || cnt == 0) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "电表未关联该商户"); } } private List listBoundElectricalIds(Integer customerId) { return ywCustomerElectricalMapper.selectList(new QueryWrapper().lambda() .eq(YwCustomerElectrical::getCustomerId, customerId) .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)) .stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toList()); } private Set listAllBoundElectricalIds() { return ywCustomerElectricalMapper.selectList(new QueryWrapper().lambda() .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)) .stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet()); } private Set listAllBoundElectricalIdsExcept(Integer customerId) { return ywCustomerElectricalMapper.selectList(new QueryWrapper().lambda() .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO) .ne(YwCustomerElectrical::getCustomerId, customerId)) .stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet()); } private List loadCustomerElectricalList(Integer customerId) { List ids = listBoundElectricalIds(customerId); if (ids.isEmpty()) { return Collections.emptyList(); } List list = ywElectricalMapper.selectBatchIds(ids); list = list.stream().filter(e -> !Objects.equals(e.getIsdeleted(), Constants.ONE)).collect(Collectors.toList()); ywElectricalBizService.enrichList(list); return list; } private List loadCustomerConditionerList(Integer customerId) { List rels = ywCustomerConditionerMapper.selectList(new QueryWrapper().lambda() .eq(YwCustomerConditioner::getCustomerId, customerId) .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO)); if (rels.isEmpty()) { return Collections.emptyList(); } Map ratioMap = rels.stream() .collect(Collectors.toMap(YwCustomerConditioner::getConditionerId, YwCustomerConditioner::getDevRatio, (a, b) -> a)); List list = ywConditionerMapper.selectBatchIds(ratioMap.keySet()); list = list.stream().filter(c -> !Objects.equals(c.getIsdeleted(), Constants.ONE)).collect(Collectors.toList()); for (YwConditioner c : list) { c.setDevRatio(ratioMap.get(c.getId())); } return list; } private PageData pageElectricalByIds(PageWrap pageWrap, List ids) { IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); YwElectrical model = pageWrap.getModel(); QueryWrapper qw = new QueryWrapper<>(); qw.lambda() .in(YwElectrical::getId, ids) .eq(YwElectrical::getIsdeleted, Constants.ZERO) .and(model != null && StringUtils.isNotBlank(model.getName()), w -> w .like(YwElectrical::getName, model.getName()) .or().like(YwElectrical::getAddress, model.getName())) .orderByDesc(YwElectrical::getCreateDate); IPage result = ywElectricalMapper.selectPage(page, qw); ywElectricalBizService.enrichList(result.getRecords()); return PageData.from(result); } private PageData emptyPage(PageWrap pageWrap) { PageData data = new PageData<>(); data.setRecords(Collections.emptyList()); data.setTotal(0); data.setPage(pageWrap.getPage()); data.setCapacity(pageWrap.getCapacity()); return data; } }