package com.ruoyi.order.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.api.feignClient.AppUserCarClient; import com.ruoyi.account.api.model.TAppUserCar; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient; import com.ruoyi.chargingPile.api.feignClient.SiteClient; import com.ruoyi.chargingPile.api.dto.GetSiteListDTO; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.common.core.web.page.PageInfo; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.order.api.model.TCardChargingOrder; import com.ruoyi.order.api.query.CardBalanceDetailQuery; import com.ruoyi.order.api.query.CardChargingOrderQuery; import com.ruoyi.order.api.vo.CardBalanceDetailVO; import com.ruoyi.order.api.vo.ChargingOrderVO; import com.ruoyi.order.mapper.TCardChargingOrderMapper; import com.ruoyi.order.service.TCardChargingOrderService; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.integration.api.model.UploadRealTimeMonitoringData; import com.ruoyi.order.util.mongodb.service.UploadRealTimeMonitoringDataService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @Service public class TCardChargingOrderServiceImpl extends ServiceImpl implements TCardChargingOrderService { @Resource private TokenService tokenService; @Resource private SiteClient siteClient; @Resource private ChargingPileClient chargingPileClient; @Resource private ChargingGunClient chargingGunClient; @Resource private AppUserCarClient appUserCarClient; @Resource private UploadRealTimeMonitoringDataService uploadRealTimeMonitoringDataService; @Override public PageInfo pageList(CardChargingOrderQuery query) { String[] timeRange = parseTimeRange(query); int pageCurr = query.getPageCurr() == null || query.getPageCurr() < 1 ? 1 : query.getPageCurr(); int pageSize = query.getPageSize() == null || query.getPageSize() < 1 ? 50 : query.getPageSize(); PageInfo pageInfo = new PageInfo<>(pageCurr, pageSize); setAuthSiteIds(query); long offset = (long) (pageCurr - 1) * pageSize; long total = baseMapper.count(query, timeRange[0], timeRange[1], timeRange[2], timeRange[3]); pageInfo.setTotal(total); List list = total == 0 ? Collections.emptyList() : baseMapper.pageList(query, timeRange[0], timeRange[1], timeRange[2], timeRange[3], offset, pageSize); fillPageExtra(list); pageInfo.setRecords(list); return pageInfo; } @Override public Map summary(CardChargingOrderQuery query) { String[] timeRange = parseTimeRange(query); setAuthSiteIds(query); Map result = baseMapper.summary(query, timeRange[0], timeRange[1], timeRange[2], timeRange[3]); if (result == null) { result = new HashMap<>(); } BigDecimal platformIncome = BigDecimal.ZERO; BigDecimal partnerIncome = BigDecimal.ZERO; Map accountingSummary = emptyAccountingSummary(); List orderIds = baseMapper.summaryOrderIds(query, timeRange[0], timeRange[1], timeRange[2], timeRange[3]); if (orderIds != null && !orderIds.isEmpty()) { int batchSize = 500; for (int i = 0; i < orderIds.size(); i += batchSize) { List batchIds = orderIds.subList(i, Math.min(i + batchSize, orderIds.size())); Map shareSummary = baseMapper.shareIncomeSummaryByOrderIds(batchIds); platformIncome = platformIncome.add(summaryDecimal(shareSummary, "platformIncome")); partnerIncome = partnerIncome.add(summaryDecimal(shareSummary, "partnerIncome")); mergeAccountingSummary(accountingSummary, baseMapper.accountingSummaryByOrderIds(batchIds)); } } result.put("platformIncome", platformIncome); result.put("partnerIncome", partnerIncome); result.put("platformIncomeTotal", platformIncome); result.put("partnerIncomeTotal", partnerIncome); result.put("capacityProportion", buildProportion(accountingSummary, "capacity")); result.put("serviceProportion", buildProportion(accountingSummary, "service")); result.put("electronicProportion", buildProportion(accountingSummary, "electric")); return result; } private Map emptyAccountingSummary() { Map summary = new HashMap<>(); for (String prefix : new String[]{"capacity", "service", "electric"}) { summary.put(prefix + "Total", BigDecimal.ZERO); for (int type = 1; type <= 4; type++) { summary.put(prefix + type, BigDecimal.ZERO); } } return summary; } private void mergeAccountingSummary(Map total, Map batch) { if (batch == null) { return; } for (String key : total.keySet()) { total.put(key, total.get(key).add(summaryDecimal(batch, key))); } } private BigDecimal summaryDecimal(Map summary, String key) { if (summary == null || summary.get(key) == null) { return BigDecimal.ZERO; } Object value = summary.get(key); return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString()); } private String buildProportion(Map summary, String prefix) { BigDecimal denominator = summary.get(prefix + "Total"); List proportions = new ArrayList<>(4); for (int type = 1; type <= 4; type++) { BigDecimal percentage = denominator.signum() == 0 ? BigDecimal.ZERO : summary.get(prefix + type).multiply(new BigDecimal("100")) .divide(denominator, 2, RoundingMode.HALF_UP).stripTrailingZeros(); proportions.add(percentage.toPlainString() + "%"); } return String.join("-", proportions); } @Override public List exportList(CardChargingOrderQuery query) { String[] timeRange = parseTimeRange(query); setAuthSiteIds(query); long total = baseMapper.count(query, timeRange[0], timeRange[1], timeRange[2], timeRange[3]); List result = new ArrayList<>(); if (total == 0) { return result; } int batchSize = 5000; for (long offset = 0; offset < total; offset += batchSize) { List batch = baseMapper.pageList(query, timeRange[0], timeRange[1], timeRange[2], timeRange[3], offset, batchSize); if (batch == null || batch.isEmpty()) { break; } result.addAll(batch); } fillPageExtra(result); return result; } @Override public Map detail(Long chargingOrderId) { TCardChargingOrder order = getById(chargingOrderId); if (order == null) { return Collections.emptyMap(); } Map result = new HashMap<>(); result.put("id", order.getId()); result.put("uid", String.valueOf(order.getId())); result.put("code", order.getCode()); result.put("cardNo", order.getCardNo()); result.put("status", order.getStatus()); result.put("siteId", order.getSiteId()); result.put("chargingPileId", order.getChargingPileId()); result.put("chargingGunId", order.getChargingGunId()); result.put("startTime", order.getStartTime()); result.put("endTime", order.getEndTime()); result.put("chargingCapacity", order.getChargingCapacity()); result.put("paymentAmount", order.getPaymentAmount()); result.put("electrovalence", order.getElectrovalence()); result.put("serviceCharge", order.getServiceCharge()); result.put("total", defaultDecimal(order.getElectrovalence()).add(defaultDecimal(order.getServiceCharge()))); result.put("realTotal", order.getPaymentAmount()); result.put("endMode", order.getEndMode()); result.put("phone", order.getPhone()); result.put("licensePlate", order.getPlateNum()); result.put("startSoc", "-"); result.put("endSoc", "-"); if (order.getStartTime() != null && order.getEndTime() != null) { result.put("chargingSecond", ChronoUnit.SECONDS.between(order.getStartTime(), order.getEndTime())); } List monitoring = uploadRealTimeMonitoringDataService.getDataByOrderCodeAsc(order.getCode()); if (monitoring == null) { monitoring = Collections.emptyList(); } for (UploadRealTimeMonitoringData data : monitoring) { if (data.getOutput_current() != null && data.getOutput_voltage() != null) { data.setPower(data.getOutput_voltage().multiply(data.getOutput_current()).divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP)); } } result.put("list", monitoring); result.put("list1", baseMapper.accountingStrategyList(order.getId())); List siteIds = order.getSiteId() == null ? Collections.emptyList() : Collections.singletonList(order.getSiteId()); if (!siteIds.isEmpty()) { List sites = Optional.ofNullable(siteClient.getSiteByIds(siteIds).getData()).orElse(Collections.emptyList()); if (!sites.isEmpty()) { result.put("siteName", sites.get(0).getName()); result.put("siteAddress", sites.get(0).getAddress()); } } if (order.getChargingGunId() != null) { TChargingGun gun = chargingGunClient.getChargingGunById(order.getChargingGunId()).getData(); if (gun != null) { result.put("gunCode", gun.getCode()); result.put("terminalName", gun.getName()); } } return result; } private BigDecimal defaultDecimal(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; } @Override public List> balanceIncomeDetail(CardChargingOrderQuery query) { return baseMapper.balanceIncomeDetail(query); } @Override public List> accountingStrategyList(Long chargingOrderId) { return baseMapper.accountingStrategyList(chargingOrderId); } @Override public PageInfo balanceDetailPage(CardBalanceDetailQuery query) { int pageCurr = query.getPageCurr() == null || query.getPageCurr() < 1 ? 1 : query.getPageCurr(); int pageSize = query.getPageSize() == null || query.getPageSize() < 1 ? 50 : query.getPageSize(); setAuthSiteIds(query); PageInfo pageInfo = new PageInfo<>(pageCurr, pageSize); long total = baseMapper.balanceDetailCount(query); pageInfo.setTotal(total); if (total == 0) { pageInfo.setRecords(Collections.emptyList()); return pageInfo; } long offset = (long) (pageCurr - 1) * pageSize; List list = baseMapper.balanceDetailList(query, offset, pageSize); pageInfo.setRecords(list); return pageInfo; } @Override public Map balanceDetailSummary(CardBalanceDetailQuery query) { setAuthSiteIds(query); Map result = baseMapper.balanceDetailSummary(query); if (result == null) { result = new HashMap<>(); } result.putIfAbsent("orderCount", 0); result.putIfAbsent("incomeAmount", BigDecimal.ZERO); result.putIfAbsent("expenseAmount", BigDecimal.ZERO); return result; } @Override public List balanceDetailExport(CardBalanceDetailQuery query) { setAuthSiteIds(query); long total = baseMapper.balanceDetailCount(query); if (total == 0) { return new ArrayList<>(); } List result = new ArrayList<>(); int batchSize = 5000; for (long offset = 0; offset < total; offset += batchSize) { List batch = baseMapper.balanceDetailList(query, offset, batchSize); if (batch == null || batch.isEmpty()) { break; } result.addAll(batch); } return result; } private void setAuthSiteIds(CardChargingOrderQuery query) { List siteIds = new ArrayList<>(); if (query.getSiteId() != null) { siteIds.add(query.getSiteId()); } else { Long userId = tokenService.getLoginUser().getUserid(); if (userId != null) { siteIds = Optional.ofNullable(siteClient.getSiteListByUserId(userId).getData()).orElse(Collections.emptyList()) .stream().map(GetSiteListDTO::getId).collect(Collectors.toList()); } } if (siteIds.isEmpty()) { siteIds.add(-1); } query.setSiteIds(siteIds); } private void setAuthSiteIds(CardBalanceDetailQuery query) { List siteIds = new ArrayList<>(); Long userId = tokenService.getLoginUser().getUserid(); if (userId != null) { siteIds = Optional.ofNullable(siteClient.getSiteListByUserId(userId).getData()).orElse(Collections.emptyList()) .stream().map(GetSiteListDTO::getId).collect(Collectors.toList()); } if (siteIds.isEmpty()) { siteIds.add(-1); } query.setSiteIds(siteIds); } private void fillPageExtra(List list) { if (list == null || list.isEmpty()) { return; } List siteIds = list.stream().map(ChargingOrderVO::getSiteId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); List gunIds = list.stream().map(ChargingOrderVO::getChargingGunId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); List carIds = list.stream().map(ChargingOrderVO::getAppUserCarId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); Map cars = carIds.isEmpty() ? Collections.emptyMap() : Optional.ofNullable(appUserCarClient.getCarByIds(carIds).getData()).orElse(Collections.emptyList()).stream() .collect(Collectors.toMap(TAppUserCar::getId, item -> item, (a, b) -> a)); Map sites = Optional.ofNullable(siteClient.getSiteByIds(siteIds).getData()).orElse(Collections.emptyList()).stream() .collect(Collectors.toMap(Site::getId, item -> item, (a, b) -> a)); Map guns = gunIds.isEmpty() ? Collections.emptyMap() : Optional.ofNullable(chargingGunClient.getChargingGunByIds(gunIds).getData()).orElse(Collections.emptyList()).stream() .collect(Collectors.toMap(TChargingGun::getId, item -> item, (a, b) -> a)); for (ChargingOrderVO item : list) { Site site = sites.get(item.getSiteId()); item.setSiteName(site == null ? null : site.getName()); TChargingGun gun = guns.get(item.getChargingGunId()); item.setTerminalName(gun == null ? null : gun.getName()); TAppUserCar car = cars.get(item.getAppUserCarId()); item.setVin(car == null ? null : car.getVin()); if (item.getStartTime() != null && item.getEndTime() != null) { item.setChargingSecond(ChronoUnit.SECONDS.between(item.getStartTime(), item.getEndTime())); } UploadRealTimeMonitoringData monitoringData = uploadRealTimeMonitoringDataService.getLastDataById(item.getCode()); if (monitoringData != null) { item.setChargeCurrent(monitoringData.getOutput_current()); item.setChargeVoltage(monitoringData.getOutput_voltage()); item.setChargePower(monitoringData.getPower()); } item.setPlatformIncome(BigDecimal.ZERO); item.setPartnerIncome(BigDecimal.ZERO); } } private String[] parseTimeRange(CardChargingOrderQuery query) { return new String[]{query.getStartTime1(), query.getStartTime2(), query.getEndTime1(), query.getEndTime2()}; } }