|
|
@@ -0,0 +1,410 @@
|
|
|
+package com.zsElectric.boot.system.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.zsElectric.boot.system.mapper.DataBoardMapper;
|
|
|
+import com.zsElectric.boot.system.model.query.HistoryBusinessQuery;
|
|
|
+import com.zsElectric.boot.system.model.query.StationRankQuery;
|
|
|
+import com.zsElectric.boot.system.model.vo.*;
|
|
|
+import com.zsElectric.boot.system.service.DataBoardService;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.YearMonth;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import java.util.stream.IntStream;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 数据看板服务实现类
|
|
|
+ *
|
|
|
+ * @author zsElectric
|
|
|
+ * @since 2026-03-09
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class DataBoardServiceImpl implements DataBoardService {
|
|
|
+
|
|
|
+ private final DataBoardMapper dataBoardMapper;
|
|
|
+
|
|
|
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+ private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DataBoardRealTimeVO getRealTimeData() {
|
|
|
+ DataBoardRealTimeVO realTimeVO = dataBoardMapper.selectRealTimeData();
|
|
|
+ if (realTimeVO == null) {
|
|
|
+ realTimeVO = new DataBoardRealTimeVO();
|
|
|
+ }
|
|
|
+ // 获取累计退款金额
|
|
|
+ BigDecimal totalRefundAmount = dataBoardMapper.selectTotalRefundAmount();
|
|
|
+ realTimeVO.setTotalRefundAmount(totalRefundAmount != null ? totalRefundAmount : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 获取累计首单金额
|
|
|
+ BigDecimal totalFirstOrderAmount = dataBoardMapper.selectTotalFirstOrderAmount();
|
|
|
+ realTimeVO.setTotalFirstOrderAmount(totalFirstOrderAmount != null ? totalFirstOrderAmount : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 确保所有字段非空
|
|
|
+ ensureRealTimeDataNotNull(realTimeVO);
|
|
|
+ return realTimeVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DataBoardTodayVO getTodayData() {
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+ String todayStart = today.atStartOfDay().format(DATETIME_FORMATTER);
|
|
|
+ String todayEnd = today.atTime(23, 59, 59).format(DATETIME_FORMATTER);
|
|
|
+
|
|
|
+ DataBoardTodayVO todayVO = dataBoardMapper.selectTodayData(todayStart, todayEnd);
|
|
|
+ if (todayVO == null) {
|
|
|
+ todayVO = new DataBoardTodayVO();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取今日退款金额
|
|
|
+ BigDecimal todayRefundAmount = dataBoardMapper.selectTodayRefundAmount(todayStart, todayEnd);
|
|
|
+ todayVO.setTodayRefundAmount(todayRefundAmount != null ? todayRefundAmount : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 获取今日首单金额
|
|
|
+ BigDecimal todayFirstOrderAmount = dataBoardMapper.selectTodayFirstOrderAmount(todayStart, todayEnd);
|
|
|
+ todayVO.setTodayFirstOrderAmount(todayFirstOrderAmount != null ? todayFirstOrderAmount : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 确保所有字段非空
|
|
|
+ ensureTodayDataNotNull(todayVO);
|
|
|
+ return todayVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ChargePowerTrendVO getChargePowerTrend(String compareDate) {
|
|
|
+ ChargePowerTrendVO trendVO = new ChargePowerTrendVO();
|
|
|
+
|
|
|
+ // 生成0-23小时列表
|
|
|
+ List<Integer> hours = IntStream.rangeClosed(0, 23).boxed().collect(Collectors.toList());
|
|
|
+ trendVO.setHours(hours);
|
|
|
+
|
|
|
+ // 今日数据
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+ String todayStart = today.atStartOfDay().format(DATETIME_FORMATTER);
|
|
|
+ String todayEnd = today.atTime(23, 59, 59).format(DATETIME_FORMATTER);
|
|
|
+ List<Map<String, Object>> todayHourlyData = dataBoardMapper.selectHourlyChargePower(todayStart, todayEnd);
|
|
|
+ Map<Integer, BigDecimal> todayMap = convertHourlyDataToMap(todayHourlyData);
|
|
|
+ List<BigDecimal> todayData = hours.stream()
|
|
|
+ .map(hour -> todayMap.getOrDefault(hour, BigDecimal.ZERO))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ trendVO.setTodayData(todayData);
|
|
|
+
|
|
|
+ // 对比日数据
|
|
|
+ LocalDate compareDateParsed;
|
|
|
+ if (StrUtil.isNotBlank(compareDate)) {
|
|
|
+ compareDateParsed = LocalDate.parse(compareDate, DATE_FORMATTER);
|
|
|
+ } else {
|
|
|
+ // 默认对比昨天
|
|
|
+ compareDateParsed = today.minusDays(1);
|
|
|
+ }
|
|
|
+ String compareDateStart = compareDateParsed.atStartOfDay().format(DATETIME_FORMATTER);
|
|
|
+ String compareDateEnd = compareDateParsed.atTime(23, 59, 59).format(DATETIME_FORMATTER);
|
|
|
+ List<Map<String, Object>> compareHourlyData = dataBoardMapper.selectHourlyChargePower(compareDateStart, compareDateEnd);
|
|
|
+ Map<Integer, BigDecimal> compareMap = convertHourlyDataToMap(compareHourlyData);
|
|
|
+ List<BigDecimal> compareData = hours.stream()
|
|
|
+ .map(hour -> compareMap.getOrDefault(hour, BigDecimal.ZERO))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ trendVO.setCompareData(compareData);
|
|
|
+ trendVO.setCompareDate(compareDateParsed.format(DATE_FORMATTER));
|
|
|
+
|
|
|
+ return trendVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public HistoryBusinessDataVO getHistoryBusinessData(HistoryBusinessQuery query) {
|
|
|
+ HistoryBusinessDataVO dataVO = new HistoryBusinessDataVO();
|
|
|
+ dataVO.setDataType(query.getDataType());
|
|
|
+ dataVO.setTimeDimension(query.getTimeDimension());
|
|
|
+
|
|
|
+ // 计算日期范围
|
|
|
+ LocalDate startDate;
|
|
|
+ LocalDate endDate;
|
|
|
+
|
|
|
+ if ("month".equalsIgnoreCase(query.getTimeDimension()) && StrUtil.isNotBlank(query.getYearMonth())) {
|
|
|
+ // 按月趋势:查询指定月份的每日数据
|
|
|
+ YearMonth yearMonth = YearMonth.parse(query.getYearMonth());
|
|
|
+ startDate = yearMonth.atDay(1);
|
|
|
+ endDate = yearMonth.atEndOfMonth();
|
|
|
+ } else {
|
|
|
+ // 按日趋势:默认查询最近30天
|
|
|
+ endDate = LocalDate.now();
|
|
|
+ startDate = endDate.minusDays(29);
|
|
|
+ }
|
|
|
+
|
|
|
+ String startDateStr = startDate.format(DATE_FORMATTER);
|
|
|
+ String endDateStr = endDate.format(DATE_FORMATTER);
|
|
|
+
|
|
|
+ List<Map<String, Object>> rawData;
|
|
|
+ String dataType = query.getDataType();
|
|
|
+ if (StrUtil.isBlank(dataType)) {
|
|
|
+ dataType = "chargePower";
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (dataType) {
|
|
|
+ case "chargeAmount":
|
|
|
+ rawData = dataBoardMapper.selectDailyChargeAmount(startDateStr, endDateStr);
|
|
|
+ break;
|
|
|
+ case "validOrders":
|
|
|
+ rawData = dataBoardMapper.selectDailyValidOrders(startDateStr, endDateStr);
|
|
|
+ break;
|
|
|
+ case "registerUsers":
|
|
|
+ rawData = dataBoardMapper.selectDailyRegisterUsers(startDateStr, endDateStr);
|
|
|
+ break;
|
|
|
+ case "chargePower":
|
|
|
+ default:
|
|
|
+ rawData = dataBoardMapper.selectDailyChargePower(startDateStr, endDateStr);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换数据
|
|
|
+ List<String> labels = new ArrayList<>();
|
|
|
+ List<BigDecimal> values = new ArrayList<>();
|
|
|
+ Map<String, BigDecimal> dataMap = new LinkedHashMap<>();
|
|
|
+ for (Map<String, Object> item : rawData) {
|
|
|
+ String label = String.valueOf(item.get("dateLabel"));
|
|
|
+ BigDecimal value = item.get("value") != null ?
|
|
|
+ new BigDecimal(String.valueOf(item.get("value"))) : BigDecimal.ZERO;
|
|
|
+ dataMap.put(label, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 填充所有日期
|
|
|
+ LocalDate current = startDate;
|
|
|
+ DateTimeFormatter labelFormatter = DateTimeFormatter.ofPattern("MM.dd");
|
|
|
+ while (!current.isAfter(endDate)) {
|
|
|
+ String label = current.format(labelFormatter);
|
|
|
+ labels.add(label);
|
|
|
+ values.add(dataMap.getOrDefault(label, BigDecimal.ZERO));
|
|
|
+ current = current.plusDays(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVO.setLabels(labels);
|
|
|
+ dataVO.setValues(values);
|
|
|
+ return dataVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public StationRankListVO getStationRankData(StationRankQuery query) {
|
|
|
+ StationRankListVO rankListVO = new StationRankListVO();
|
|
|
+
|
|
|
+ // 计算时间范围
|
|
|
+ LocalDate startDate;
|
|
|
+ LocalDate endDate = LocalDate.now();
|
|
|
+ String timeRange = query.getTimeRange();
|
|
|
+ if (StrUtil.isBlank(timeRange)) {
|
|
|
+ timeRange = "week";
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (timeRange) {
|
|
|
+ case "today":
|
|
|
+ startDate = endDate;
|
|
|
+ break;
|
|
|
+ case "month":
|
|
|
+ startDate = endDate.minusDays(29);
|
|
|
+ break;
|
|
|
+ case "custom":
|
|
|
+ if (StrUtil.isNotBlank(query.getStartDate()) && StrUtil.isNotBlank(query.getEndDate())) {
|
|
|
+ startDate = LocalDate.parse(query.getStartDate(), DATE_FORMATTER);
|
|
|
+ endDate = LocalDate.parse(query.getEndDate(), DATE_FORMATTER);
|
|
|
+ } else {
|
|
|
+ startDate = endDate.minusDays(6);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case "week":
|
|
|
+ default:
|
|
|
+ startDate = endDate.minusDays(6);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ String startDateStr = startDate.format(DATE_FORMATTER);
|
|
|
+ String endDateStr = endDate.format(DATE_FORMATTER);
|
|
|
+
|
|
|
+ // 计算前一个周期的日期范围(用于波动计算)
|
|
|
+ long daysDiff = java.time.temporal.ChronoUnit.DAYS.between(startDate, endDate) + 1;
|
|
|
+ LocalDate prevStartDate = startDate.minusDays(daysDiff);
|
|
|
+ LocalDate prevEndDate = startDate.minusDays(1);
|
|
|
+ String prevStartDateStr = prevStartDate.format(DATE_FORMATTER);
|
|
|
+ String prevEndDateStr = prevEndDate.format(DATE_FORMATTER);
|
|
|
+
|
|
|
+ // 获取热门充电站
|
|
|
+ List<StationRankVO> hotStations = dataBoardMapper.selectHotStations(startDateStr, endDateStr, 5);
|
|
|
+ // 设置排名
|
|
|
+ for (int i = 0; i < hotStations.size(); i++) {
|
|
|
+ hotStations.get(i).setRank(i + 1);
|
|
|
+ }
|
|
|
+ rankListVO.setHotStations(hotStations);
|
|
|
+
|
|
|
+ // 计算波动充电站(基于充电度数波动)
|
|
|
+ List<StationRankVO> fluctuationStations = calculateFluctuationStations(
|
|
|
+ hotStations, prevStartDateStr, prevEndDateStr, startDateStr, endDateStr);
|
|
|
+ rankListVO.setFluctuationStations(fluctuationStations);
|
|
|
+
|
|
|
+ // 设置日期范围描述
|
|
|
+ rankListVO.setDateRange(startDateStr + " 至 " + endDateStr);
|
|
|
+
|
|
|
+ return rankListVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public UserChurnRateVO getUserChurnRate() {
|
|
|
+ UserChurnRateVO churnRateVO = new UserChurnRateVO();
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+
|
|
|
+ // 计算近7天流失率
|
|
|
+ BigDecimal sevenDayRate = calculateChurnRate(today.minusDays(14), today.minusDays(7),
|
|
|
+ today.minusDays(6), today);
|
|
|
+ churnRateVO.setSevenDayChurnRate(sevenDayRate);
|
|
|
+
|
|
|
+ // 计算近1个月流失率
|
|
|
+ BigDecimal oneMonthRate = calculateChurnRate(today.minusDays(60), today.minusDays(30),
|
|
|
+ today.minusDays(29), today);
|
|
|
+ churnRateVO.setOneMonthChurnRate(oneMonthRate);
|
|
|
+
|
|
|
+ // 计算近3个月流失率
|
|
|
+ BigDecimal threeMonthRate = calculateChurnRate(today.minusDays(180), today.minusDays(90),
|
|
|
+ today.minusDays(89), today);
|
|
|
+ churnRateVO.setThreeMonthChurnRate(threeMonthRate);
|
|
|
+
|
|
|
+ return churnRateVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算流失率
|
|
|
+ */
|
|
|
+ private BigDecimal calculateChurnRate(LocalDate earlyStart, LocalDate earlyEnd,
|
|
|
+ LocalDate recentStart, LocalDate recentEnd) {
|
|
|
+ String earlyStartStr = earlyStart.format(DATE_FORMATTER);
|
|
|
+ String earlyEndStr = earlyEnd.format(DATE_FORMATTER);
|
|
|
+ String recentStartStr = recentStart.format(DATE_FORMATTER);
|
|
|
+ String recentEndStr = recentEnd.format(DATE_FORMATTER);
|
|
|
+
|
|
|
+ Long activeCount = dataBoardMapper.selectActiveUserCount(earlyStartStr, earlyEndStr);
|
|
|
+ if (activeCount == null || activeCount == 0) {
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ Long churnCount = dataBoardMapper.selectChurnUserCount(earlyStartStr, earlyEndStr, recentStartStr, recentEndStr);
|
|
|
+ if (churnCount == null) {
|
|
|
+ churnCount = 0L;
|
|
|
+ }
|
|
|
+
|
|
|
+ return BigDecimal.valueOf(churnCount)
|
|
|
+ .multiply(BigDecimal.valueOf(100))
|
|
|
+ .divide(BigDecimal.valueOf(activeCount), 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算波动充电站
|
|
|
+ */
|
|
|
+ private List<StationRankVO> calculateFluctuationStations(List<StationRankVO> hotStations,
|
|
|
+ String prevStartDate, String prevEndDate,
|
|
|
+ String currStartDate, String currEndDate) {
|
|
|
+ List<StationRankVO> fluctuationStations = new ArrayList<>();
|
|
|
+
|
|
|
+ for (StationRankVO station : hotStations) {
|
|
|
+ if (station.getStationId() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ StationRankVO fluctuationStation = new StationRankVO();
|
|
|
+ fluctuationStation.setRank(station.getRank());
|
|
|
+ fluctuationStation.setStationId(station.getStationId());
|
|
|
+ fluctuationStation.setStationName(station.getStationName());
|
|
|
+ fluctuationStation.setChargePower(station.getChargePower());
|
|
|
+
|
|
|
+ // 获取前一周期的充电度数
|
|
|
+ BigDecimal prevPower = dataBoardMapper.selectStationChargePower(
|
|
|
+ String.valueOf(station.getStationId()), prevStartDate, prevEndDate);
|
|
|
+ if (prevPower == null) {
|
|
|
+ prevPower = BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal currPower = station.getChargePower();
|
|
|
+ if (currPower == null) {
|
|
|
+ currPower = BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算波动百分比
|
|
|
+ if (prevPower.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
+ if (currPower.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ fluctuationStation.setFluctuation(BigDecimal.valueOf(100));
|
|
|
+ fluctuationStation.setFluctuationDirection("up");
|
|
|
+ } else {
|
|
|
+ fluctuationStation.setFluctuation(BigDecimal.ZERO);
|
|
|
+ fluctuationStation.setFluctuationDirection("up");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ BigDecimal diff = currPower.subtract(prevPower);
|
|
|
+ BigDecimal fluctuation = diff.multiply(BigDecimal.valueOf(100))
|
|
|
+ .divide(prevPower, 2, RoundingMode.HALF_UP).abs();
|
|
|
+ fluctuationStation.setFluctuation(fluctuation);
|
|
|
+ fluctuationStation.setFluctuationDirection(diff.compareTo(BigDecimal.ZERO) >= 0 ? "up" : "down");
|
|
|
+ }
|
|
|
+
|
|
|
+ fluctuationStations.add(fluctuationStation);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 按波动幅度排序
|
|
|
+ fluctuationStations.sort((a, b) -> b.getFluctuation().compareTo(a.getFluctuation()));
|
|
|
+
|
|
|
+ // 重新设置排名
|
|
|
+ for (int i = 0; i < fluctuationStations.size(); i++) {
|
|
|
+ fluctuationStations.get(i).setRank(i + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return fluctuationStations;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将小时数据转换为Map
|
|
|
+ */
|
|
|
+ private Map<Integer, BigDecimal> convertHourlyDataToMap(List<Map<String, Object>> hourlyData) {
|
|
|
+ Map<Integer, BigDecimal> map = new HashMap<>();
|
|
|
+ for (Map<String, Object> item : hourlyData) {
|
|
|
+ Integer hour = ((Number) item.get("hour")).intValue();
|
|
|
+ BigDecimal power = item.get("chargePower") != null ?
|
|
|
+ new BigDecimal(String.valueOf(item.get("chargePower"))) : BigDecimal.ZERO;
|
|
|
+ map.put(hour, power);
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 确保实时数据所有字段非空
|
|
|
+ */
|
|
|
+ private void ensureRealTimeDataNotNull(DataBoardRealTimeVO vo) {
|
|
|
+ if (vo.getTotalChargePower() == null) vo.setTotalChargePower(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalChargeAmount() == null) vo.setTotalChargeAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalDiscountAmount() == null) vo.setTotalDiscountAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalServiceFeeAmount() == null) vo.setTotalServiceFeeAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalRefundAmount() == null) vo.setTotalRefundAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalActualPayAmount() == null) vo.setTotalActualPayAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalFirstOrderAmount() == null) vo.setTotalFirstOrderAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalCouponAmount() == null) vo.setTotalCouponAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalFirmDiscountAmount() == null) vo.setTotalFirmDiscountAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTotalCommissionAmount() == null) vo.setTotalCommissionAmount(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 确保今日数据所有字段非空
|
|
|
+ */
|
|
|
+ private void ensureTodayDataNotNull(DataBoardTodayVO vo) {
|
|
|
+ if (vo.getTodayChargePower() == null) vo.setTodayChargePower(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayChargeAmount() == null) vo.setTodayChargeAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayDiscountAmount() == null) vo.setTodayDiscountAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayServiceFeeAmount() == null) vo.setTodayServiceFeeAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayRefundAmount() == null) vo.setTodayRefundAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayActualPayAmount() == null) vo.setTodayActualPayAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayFirstOrderAmount() == null) vo.setTodayFirstOrderAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayCouponAmount() == null) vo.setTodayCouponAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayFirmDiscountAmount() == null) vo.setTodayFirmDiscountAmount(BigDecimal.ZERO);
|
|
|
+ if (vo.getTodayCommissionAmount() == null) vo.setTodayCommissionAmount(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+}
|