package com.doumee.service.business.impl; 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.constants.Constants; import com.doumee.core.constants.ResponseStatus; import com.doumee.core.exception.BusinessException; import com.doumee.core.model.PageData; import com.doumee.core.model.PageWrap; import com.doumee.core.utils.Utils; import com.doumee.dao.business.*; import com.doumee.dao.business.model.*; import com.doumee.dao.dto.RevenueQueryDTO; import com.doumee.dao.vo.RevenueStatisticsVO; import com.doumee.dao.vo.RevenueSummaryVO; import com.doumee.service.business.RevenueService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.doumee.dao.dto.ShopRevenueQueryDTO; import com.doumee.dao.vo.DriverKpiVO; import com.doumee.dao.vo.DriverOrderTrendVO; import com.doumee.dao.vo.DriverRewardHallVO; import com.doumee.biz.system.OperationConfigBiz; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; /** * 收支记录Service实现 * @author rk * @date 2026/04/10 */ @Service public class RevenueServiceImpl implements RevenueService { @Autowired private RevenueMapper revenueMapper; @Autowired private WithdrawalOrdersMapper withdrawalOrdersMapper; @Autowired private ShopInfoMapper shopInfoMapper; @Autowired private MemberMapper memberMapper; @Autowired private DriverInfoMapper driverInfoMapper; @Autowired private OrdersMapper ordersMapper; @Autowired private RewardRecordMapper rewardRecordMapper; @Autowired private OperationConfigBiz operationConfigBiz; @Override public Integer create(Revenue revenue) { revenueMapper.insert(revenue); return revenue.getId(); } @Override public void deleteById(Integer id) { revenueMapper.update(new UpdateWrapper().lambda() .set(Revenue::getDeleted, Constants.ONE) .eq(Revenue::getId, id)); } @Override public void delete(Revenue revenue) { UpdateWrapper deleteWrapper = new UpdateWrapper<>(revenue); revenueMapper.delete(deleteWrapper); } @Override public void deleteByIdInBatch(List ids) { if (ids == null || ids.isEmpty()) { return; } revenueMapper.deleteBatchIds(ids); } @Override public void updateById(Revenue revenue) { revenueMapper.updateById(revenue); } @Override public void updateByIdInBatch(List revenues) { if (revenues == null || revenues.isEmpty()) { return; } for (Revenue revenue : revenues) { this.updateById(revenue); } } @Override public Revenue findById(Integer id) { Revenue revenue = revenueMapper.selectById(id); if (Objects.isNull(revenue)) { throw new BusinessException(ResponseStatus.DATA_EMPTY); } return revenue; } @Override public Revenue findOne(Revenue revenue) { QueryWrapper wrapper = new QueryWrapper<>(revenue); return revenueMapper.selectOne(wrapper); } @Override public List findList(Revenue revenue) { QueryWrapper wrapper = new QueryWrapper<>(revenue); return revenueMapper.selectList(wrapper); } @Override public PageData findPage(PageWrap pageWrap) { IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); QueryWrapper queryWrapper = new QueryWrapper<>(); Utils.MP.blankToNull(pageWrap.getModel()); pageWrap.getModel().setDeleted(Constants.ZERO); // 用户主键 if (pageWrap.getModel().getMemberId() != null) { queryWrapper.lambda().eq(Revenue::getMemberId, pageWrap.getModel().getMemberId()); } // 时间范围 if (pageWrap.getModel().getStartTime() != null) { queryWrapper.lambda().ge(Revenue::getCreateTime, pageWrap.getModel().getStartTime()); } if (pageWrap.getModel().getEndTime() != null) { queryWrapper.lambda().le(Revenue::getCreateTime, pageWrap.getModel().getEndTime()); } // 收支类型 if (pageWrap.getModel().getOptType() != null) { queryWrapper.lambda().eq(Revenue::getOptType, pageWrap.getModel().getOptType()); } // 订单号模糊查询 if (StringUtils.isNotBlank(pageWrap.getModel().getOrderNo())) { queryWrapper.lambda().like(Revenue::getOrderNo, pageWrap.getModel().getOrderNo()); } // 是否生效 if (pageWrap.getModel().getVaildStatus() != null) { queryWrapper.lambda().eq(Revenue::getVaildStatus, pageWrap.getModel().getVaildStatus()); } // 默认按创建时间倒序 queryWrapper.lambda().orderByDesc(Revenue::getCreateTime); for (PageWrap.SortData sortData : pageWrap.getSorts()) { if (sortData.getDirection().equalsIgnoreCase(PageWrap.DESC)) { queryWrapper.orderByDesc(sortData.getProperty()); } else { queryWrapper.orderByAsc(sortData.getProperty()); } } PageData result = PageData.from(revenueMapper.selectPage(page, queryWrapper)); // 金额分转元 if (result != null && result.getRecords() != null) { for (Revenue model : result.getRecords()) { model.setAmountInfo(Constants.getFormatMoney(model.getAmount())); } } return result; } @Override public long count(Revenue revenue) { QueryWrapper wrapper = new QueryWrapper<>(revenue); return revenueMapper.selectCount(wrapper); } @Override public RevenueStatisticsVO getShopRevenueStatistics(Integer shopId) { ShopInfo shop = shopInfoMapper.selectById(shopId); if (shop == null || Constants.equalsInteger(shop.getDeleted(), Constants.ONE)) { throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "门店不存在"); } return buildRevenueStatistics(shop.getId(), Constants.TWO, shop.getBalance()); } @Override public RevenueStatisticsVO getDriverRevenueStatistics(Integer memberId) { DriverInfo driverInfo = driverInfoMapper.selectById(memberId); if (driverInfo == null) { throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在"); } return buildRevenueStatistics(memberId, Constants.ONE, driverInfo.getBalance()); } /** * 构建收益统计 * * @param memberId 会员主键 * @param memberType 会员类型:1=司机;2=门店 * @param balance 当前余额(分) */ private RevenueStatisticsVO buildRevenueStatistics(Integer memberId, Integer memberType, Long balance) { RevenueStatisticsVO vo = new RevenueStatisticsVO(); vo.setBalance(balance != null ? balance : 0L); // 待结算金额:revenue中 vaildStatus=0 且 type=0(完成订单)的收入之和 QueryWrapper pendingWrapper = new QueryWrapper<>(); pendingWrapper.select("IFNULL(SUM(AMOUNT), 0) as amount") .eq("MEMBER_ID", memberId) .eq("MEMBER_TYPE", memberType) .eq("VAILD_STATUS", Constants.ZERO) .eq("TYPE", Constants.ZERO) .eq("OPT_TYPE", Constants.ONE) .eq("DELETED", Constants.ZERO); Map pendingResult = revenueMapper.selectMaps(pendingWrapper).stream().findFirst().orElse(null); vo.setPendingAmount(pendingResult != null && pendingResult.get("amount") != null ? Long.parseLong(pendingResult.get("amount").toString()) : 0L); // 累计提现金额:withdrawal_orders中 status=1(提现成功)且 type=0(提现) QueryWrapper successWrapper = new QueryWrapper<>(); successWrapper.select("IFNULL(SUM(AMOUNT), 0) as amount") .eq("MEMBER_ID", memberId) .eq("MEMBER_TYPE", memberType) .eq("STATUS", Constants.ONE) .eq("TYPE", Constants.ZERO) .eq("DELETED", Constants.ZERO); Map successResult = withdrawalOrdersMapper.selectMaps(successWrapper).stream().findFirst().orElse(null); vo.setTotalWithdrawn(successResult != null && successResult.get("amount") != null ? Long.parseLong(successResult.get("amount").toString()) : 0L); // 提现中金额:withdrawal_orders中 status=0(提现申请中)且 type=0(提现) QueryWrapper progressWrapper = new QueryWrapper<>(); progressWrapper.select("IFNULL(SUM(AMOUNT), 0) as amount") .eq("MEMBER_ID", memberId) .eq("MEMBER_TYPE", memberType) .eq("STATUS", Constants.ZERO) .eq("TYPE", Constants.ZERO) .eq("DELETED", Constants.ZERO); Map progressResult = withdrawalOrdersMapper.selectMaps(progressWrapper).stream().findFirst().orElse(null); vo.setWithdrawingAmount(progressResult != null && progressResult.get("amount") != null ? Long.parseLong(progressResult.get("amount").toString()) : 0L); return vo; } @Override public PageData findDriverRevenuePage(PageWrap pageWrap, Integer memberId) { IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); QueryWrapper qw = buildRevenueQueryWrapper(pageWrap.getModel(), memberId); PageData result = PageData.from(revenueMapper.selectPage(page, qw)); if (result != null && result.getRecords() != null) { for (Revenue model : result.getRecords()) { model.setAmountInfo(Constants.getFormatMoney(model.getAmount())); } } return result; } @Override public PageData findShopRevenuePage(PageWrap pageWrap, Integer shopId) { ShopInfo shop = shopInfoMapper.selectById(shopId); if (shop == null || Constants.equalsInteger(shop.getDeleted(), Constants.ONE)) { throw new BusinessException(ResponseStatus.DATA_EMPTY); } IPage page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); QueryWrapper qw = buildRevenueQueryWrapper(pageWrap.getModel(), shop.getId()); PageData result = PageData.from(revenueMapper.selectPage(page, qw)); if (result != null && result.getRecords() != null) { for (Revenue model : result.getRecords()) { model.setAmountInfo(Constants.getFormatMoney(model.getAmount())); } } return result; } @Override public RevenueSummaryVO getDriverRevenueSummary(RevenueQueryDTO queryDTO, Integer memberId) { return buildRevenueSummary(queryDTO, memberId); } @Override public RevenueSummaryVO getShopRevenueSummary(RevenueQueryDTO queryDTO, Integer shopId) { ShopInfo shop = shopInfoMapper.selectById(shopId); if (shop == null || Constants.equalsInteger(shop.getDeleted(), Constants.ONE)) { throw new BusinessException(ResponseStatus.DATA_EMPTY); } return buildRevenueSummary(queryDTO, shop.getId()); } private QueryWrapper buildRevenueQueryWrapper(RevenueQueryDTO query, Integer memberId) { QueryWrapper qw = new QueryWrapper<>(); qw.lambda().eq(Revenue::getDeleted, Constants.ZERO); qw.lambda().eq(Revenue::getMemberId, memberId); if (query != null) { if (query.getOptType() != null) { qw.lambda().eq(Revenue::getOptType, query.getOptType()); } if (query.getType() != null) { qw.lambda().eq(Revenue::getType, query.getType()); } if (query.getStartTime() != null) { qw.lambda().ge(Revenue::getCreateTime, query.getStartTime()); } if (query.getEndTime() != null) { qw.lambda().le(Revenue::getCreateTime, Utils.Date.getEnd(query.getEndTime())); } } qw.lambda().orderByDesc(Revenue::getCreateTime); return qw; } private RevenueSummaryVO buildRevenueSummary(RevenueQueryDTO queryDTO, Integer memberId) { // 收入 QueryWrapper incomeQw = new QueryWrapper<>(); incomeQw.eq("DELETED", Constants.ZERO); incomeQw.eq("MEMBER_ID", memberId); incomeQw.eq("OPT_TYPE", Constants.ONE); if (queryDTO != null) { if (queryDTO.getType() != null) { incomeQw.eq("TYPE", queryDTO.getType()); } if (queryDTO.getStartTime() != null) { incomeQw.ge("CREATE_TIME", queryDTO.getStartTime()); } if (queryDTO.getEndTime() != null) { incomeQw.le("CREATE_TIME", Utils.Date.getEnd(queryDTO.getEndTime())); } } incomeQw.select("IFNULL(SUM(AMOUNT), 0) as amount"); Map incomeResult = revenueMapper.selectMaps(incomeQw).stream().findFirst().orElse(null); long totalIncome = incomeResult != null && incomeResult.get("amount") != null ? Long.parseLong(incomeResult.get("amount").toString()) : 0L; // 支出 QueryWrapper expenseQw = new QueryWrapper<>(); expenseQw.eq("DELETED", Constants.ZERO); expenseQw.eq("MEMBER_ID", memberId); expenseQw.eq("OPT_TYPE", -Constants.ONE); if (queryDTO != null) { if (queryDTO.getType() != null) { expenseQw.eq("TYPE", queryDTO.getType()); } if (queryDTO.getStartTime() != null) { expenseQw.ge("CREATE_TIME", queryDTO.getStartTime()); } if (queryDTO.getEndTime() != null) { expenseQw.le("CREATE_TIME", Utils.Date.getEnd(queryDTO.getEndTime())); } } expenseQw.select("IFNULL(SUM(AMOUNT), 0) as amount"); Map expenseResult = revenueMapper.selectMaps(expenseQw).stream().findFirst().orElse(null); long totalExpense = expenseResult != null && expenseResult.get("amount") != null ? Long.parseLong(expenseResult.get("amount").toString()) : 0L; RevenueSummaryVO vo = new RevenueSummaryVO(); vo.setTotalIncome(totalIncome); vo.setTotalExpense(totalExpense); return vo; } @Override public DriverKpiVO getDriverKpi(Integer driverId, ShopRevenueQueryDTO query) { QueryWrapper qw = new QueryWrapper<>(); qw.lambda() .eq(Orders::getDeleted, Constants.ZERO) .eq(Orders::getType, Constants.ONE) .eq(Orders::getAcceptDriver, driverId) .in(Orders::getStatus, Constants.OrderStatus.waitDeposit.getKey(), Constants.OrderStatus.deposited.getKey(), Constants.OrderStatus.accepted.getKey(), Constants.OrderStatus.delivering.getKey(), Constants.OrderStatus.arrived.getKey(), Constants.OrderStatus.finished.getKey()); if (query.getStartDate() != null) { qw.lambda().ge(Orders::getCreateTime, query.getStartDate()); } if (query.getEndDate() != null) { qw.lambda().le(Orders::getCreateTime, Utils.Date.getEnd(query.getEndDate())); } List orders = ordersMapper.selectList(qw); DriverKpiVO vo = new DriverKpiVO(); vo.setTotalOrderCount(orders.size()); // 总完成订单量 long finishedCount = orders.stream() .filter(o -> Constants.equalsInteger(o.getStatus(), Constants.OrderStatus.finished.getStatus())) .count(); vo.setFinishedOrderCount((int) finishedCount); // 总营收金额 long totalRevenue = orders.stream() .mapToLong(o -> { long total = o.getTotalAmount() != null ? o.getTotalAmount() : 0L; long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L; return total - refund; }).sum(); vo.setTotalRevenue(totalRevenue); // 司机分成金额 long driverFee = orders.stream() .mapToLong(o -> o.getDriverFee() != null ? o.getDriverFee() : 0L) .sum(); vo.setDriverFeeTotal(driverFee); // 退款单数 long refundCount = orders.stream() .filter(o -> o.getRefundAmount() != null && o.getRefundAmount() > 0) .count(); vo.setRefundOrderCount((int) refundCount); // 责任扣款总额:Revenue memberId=driverId, memberType=1, type=4 QueryWrapper revQw = new QueryWrapper<>(); revQw.lambda() .eq(Revenue::getMemberId, driverId) .eq(Revenue::getMemberType, Constants.ONE) .eq(Revenue::getType, Constants.FOUR) .eq(Revenue::getDeleted, Constants.ZERO); if (query.getStartDate() != null) { revQw.lambda().ge(Revenue::getCreateTime, query.getStartDate()); } if (query.getEndDate() != null) { revQw.lambda().le(Revenue::getCreateTime, Utils.Date.getEnd(query.getEndDate())); } List deductRecords = revenueMapper.selectList(revQw); long deductTotal = deductRecords.stream() .mapToLong(r -> r.getAmount() != null ? r.getAmount() : 0L) .sum(); vo.setDeductTotal(deductTotal); return vo; } @Override public List getDriverOrderTrend(Integer driverId) { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd"); // 构建近7天日期列表 List dateList = new ArrayList<>(); for (int i = 6; i >= 0; i--) { Calendar c = Calendar.getInstance(); c.add(Calendar.DAY_OF_MONTH, -i); dateList.add(sdf.format(c.getTime())); } // 查询近7天订单 Calendar startCal = Calendar.getInstance(); startCal.add(Calendar.DAY_OF_MONTH, -6); startCal.set(Calendar.HOUR_OF_DAY, 0); startCal.set(Calendar.MINUTE, 0); startCal.set(Calendar.SECOND, 0); startCal.set(Calendar.MILLISECOND, 0); QueryWrapper qw = new QueryWrapper<>(); qw.lambda() .eq(Orders::getDeleted, Constants.ZERO) .eq(Orders::getAcceptDriver, driverId) .in(Orders::getStatus, Constants.OrderStatus.accepted.getKey(), Constants.OrderStatus.delivering.getKey(), Constants.OrderStatus.arrived.getKey(), Constants.OrderStatus.finished.getKey()) .ge(Orders::getCreateTime, startCal.getTime()); List orders = ordersMapper.selectList(qw); // 按日期分组统计 Map countMap = orders.stream() .collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime()), Collectors.counting())); List result = new ArrayList<>(); for (String date : dateList) { DriverOrderTrendVO item = new DriverOrderTrendVO(); item.setDate(date); item.setOrderCount(countMap.getOrDefault(date, 0L).intValue()); result.add(item); } return result; } @Override public DriverRewardHallVO getDriverRewardHall(Integer driverId) { // 查询已领取金额(status=1) QueryWrapper claimedQw = new QueryWrapper<>(); claimedQw.select("IFNULL(SUM(AMOUNT), 0) as amount") .eq("DRIVER_ID", driverId) .eq("STATUS", Constants.ONE) .eq("DELETED", Constants.ZERO); Map claimedResult = rewardRecordMapper.selectMaps(claimedQw).stream().findFirst().orElse(null); long claimedAmount = claimedResult != null && claimedResult.get("amount") != null ? Long.parseLong(claimedResult.get("amount").toString()) : 0L; // 查询待领取金额(status=0) QueryWrapper pendingQw = new QueryWrapper<>(); pendingQw.select("IFNULL(SUM(AMOUNT), 0) as amount") .eq("DRIVER_ID", driverId) .eq("STATUS", Constants.ZERO) .eq("DELETED", Constants.ZERO); Map pendingResult = rewardRecordMapper.selectMaps(pendingQw).stream().findFirst().orElse(null); long pendingAmount = pendingResult != null && pendingResult.get("amount") != null ? Long.parseLong(pendingResult.get("amount").toString()) : 0L; // 读取奖励规则配置 com.doumee.dao.dto.OperationConfigDTO config = operationConfigBiz.getConfig(); // 查询奖励记录列表(按主键、创建时间升序) List records = rewardRecordMapper.selectList(new QueryWrapper().lambda() .eq(RewardRecord::getDriverId, driverId) .eq(RewardRecord::getDeleted, Constants.ZERO) .orderByAsc(RewardRecord::getId) .orderByAsc(RewardRecord::getCreateTime)); DriverRewardHallVO vo = new DriverRewardHallVO(); vo.setClaimedAmount(claimedAmount); vo.setPendingAmount(pendingAmount); vo.setRegisterRewardOrderCount(config.getRegisterRewardOrderCount()); vo.setRegisterRewardAmount(config.getRegisterRewardAmount()); vo.setPlatformRewardOrderCount(config.getPlatformRewardOrderCount()); vo.setPlatformRewardAmount(config.getPlatformRewardAmount()); vo.setRecords(records); return vo; } @Override public void claimReward(Integer driverId, Integer rewardRecordId) { // 查询奖励记录 RewardRecord record = rewardRecordMapper.selectById(rewardRecordId); if (record == null || Constants.equalsInteger(record.getDeleted(), Constants.ONE)) { throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "奖励记录不存在"); } if (!Constants.equalsInteger(record.getDriverId(), driverId)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权领取该奖励"); } if (!Constants.equalsInteger(record.getStatus(), Constants.ZERO)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该奖励已领取"); } Long rewardAmount = record.getAmount() != null ? record.getAmount() : 0L; if (rewardAmount <= 0) return; // 查询司机信息 DriverInfo driver = driverInfoMapper.selectById(driverId); if (driver == null) { throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在"); } // 创建收益记录(type=3 平台奖励, optType=1 收入, vaildStatus=1 已入账) Revenue revenue = new Revenue(); revenue.setMemberId(driver.getMemberId()); revenue.setMemberType(Constants.ONE); revenue.setType(Constants.THREE); // 平台奖励 revenue.setOptType(Constants.ONE); // 收入 revenue.setAmount(rewardAmount); revenue.setVaildStatus(Constants.ONE); // 已入账 revenue.setObjId(record.getOrderId()); revenue.setObjType(Constants.ZERO); revenue.setStatus(Constants.ZERO); revenue.setDeleted(Constants.ZERO); revenue.setCreateTime(new Date()); revenueMapper.insert(revenue); // 更新奖励记录:status=1已领取, claimTime, revenueId record.setStatus(Constants.ONE); record.setClaimTime(new Date()); record.setRevenueId(revenue.getId()); record.setUpdateTime(new Date()); rewardRecordMapper.updateById(record); // 更新司机余额 driverInfoMapper.update(new UpdateWrapper().lambda() .setSql("BALANCE = IFNULL(BALANCE, 0) + " + rewardAmount) .setSql("TOTAL_BALANCE = IFNULL(TOTAL_BALANCE, 0) + " + rewardAmount) .eq(DriverInfo::getId, driverId)); } }