2 Commits

Author SHA1 Message Date
tianyongbao
a5a3eaf893 fix: 分润,讨论后,发现问题统一修复。 2026-06-03 23:17:10 +08:00
tianyongbao
771d46edbb fix: 分润发现问题,统一修复。 2026-05-30 16:42:12 +08:00
12 changed files with 416 additions and 69 deletions

View File

@@ -5,6 +5,7 @@ import java.util.Arrays;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.limap.common.core.domain.entity.SysUser;
import com.limap.common.core.domain.entity.SysRole;
import com.limap.common.utils.StringUtils;
import com.limap.core.basic.service.IBasicUserWithdrawService;
@@ -40,6 +41,10 @@ import com.limap.core.basic.vo.SharingRecordSearchVo;
@RestController
@RequestMapping("/basic/sharingRecord")
public class BasicProfitSharingRecordController extends BaseController {
private static final String DATA_SCOPE_ALL = "1";
private static final String DATA_SCOPE_DEPT = "3";
private static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
@Autowired
private IBasicProfitSharingRecordService basicProfitSharingRecordService;
@Autowired
@@ -53,10 +58,7 @@ public class BasicProfitSharingRecordController extends BaseController {
@GetMapping("/list")
public TableDataInfo list(BasicProfitSharingRecord basicProfitSharingRecord) {
startPage();
List<SysRole> roles = getLoginUser().getUser().getRoles();
if(roles.stream().noneMatch(role -> role.getRoleId().compareTo(100L) <0)){
basicProfitSharingRecord.setUserId(getUserId());
}
applySharingRecordDataScope(basicProfitSharingRecord);
List<BasicProfitSharingRecord> list = basicProfitSharingRecordService.selectBasicProfitSharingRecordList(basicProfitSharingRecord);
return getDataTable(list);
}
@@ -66,12 +68,7 @@ public class BasicProfitSharingRecordController extends BaseController {
@PreAuthorize("@ss.hasPermi('basic:sharingRecord:list')")
@GetMapping("/report")
public AjaxResult reportData(SharingRecordSearchVo searchVo) {
List<SysRole> roles = getLoginUser().getUser().getRoles();
if(roles.stream().noneMatch(role -> role.getRoleId().compareTo(100L) >=0)){
searchVo.setUserId(getUserId());
}else{
searchVo.setDeptId(getDeptId());
}
applySharingRecordDataScope(searchVo);
Map<String, Object> resultMap = basicProfitSharingRecordService.getReportData(searchVo);
return success(resultMap);
}
@@ -84,6 +81,7 @@ public class BasicProfitSharingRecordController extends BaseController {
@Log(title = "分润记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, BasicProfitSharingRecord basicProfitSharingRecord) {
applySharingRecordDataScope(basicProfitSharingRecord);
List<BasicProfitSharingRecord> list = basicProfitSharingRecordService.selectBasicProfitSharingRecordList(basicProfitSharingRecord);
ExcelUtil<BasicProfitSharingRecord> util = new ExcelUtil<BasicProfitSharingRecord>(BasicProfitSharingRecord.class);
util.exportExcel(response, list, "分润记录数据");
@@ -149,4 +147,40 @@ public class BasicProfitSharingRecordController extends BaseController {
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(basicProfitSharingRecordService.removeByIds(Arrays.asList(ids)));
}
private void applySharingRecordDataScope(BasicProfitSharingRecord record) {
SysUser user = getLoginUser().getUser();
if (user == null || user.isAdmin() || hasDataScope(user.getRoles(), DATA_SCOPE_ALL)) {
return;
}
if (hasDataScope(user.getRoles(), DATA_SCOPE_DEPT_AND_CHILD)) {
record.getParams().put("scopeType", "deptAndChild");
record.getParams().put("scopeDeptId", getDeptId());
} else if (hasDataScope(user.getRoles(), DATA_SCOPE_DEPT)) {
record.getParams().put("scopeType", "dept");
record.getParams().put("scopeDeptId", getDeptId());
} else {
record.setUserId(getUserId());
}
}
private void applySharingRecordDataScope(SharingRecordSearchVo searchVo) {
SysUser user = getLoginUser().getUser();
if (user == null || user.isAdmin() || hasDataScope(user.getRoles(), DATA_SCOPE_ALL)) {
return;
}
if (hasDataScope(user.getRoles(), DATA_SCOPE_DEPT_AND_CHILD)) {
searchVo.setDeptId(getDeptId());
searchVo.getParams().put("scopeType", "deptAndChild");
} else if (hasDataScope(user.getRoles(), DATA_SCOPE_DEPT)) {
searchVo.setDeptId(getDeptId());
searchVo.getParams().put("scopeType", "dept");
} else {
searchVo.setUserId(getUserId());
}
}
private boolean hasDataScope(List<SysRole> roles, String dataScope) {
return roles != null && roles.stream().anyMatch(role -> dataScope.equals(role.getDataScope()));
}
}

View File

@@ -2,7 +2,10 @@ package com.limap.core.basic.domain;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -109,4 +112,20 @@ public class BasicProfitSharingRecord {
@ApiModelProperty("查询结束时间")
@TableField(exist = false)
private Date endTime;
/** 请求参数 */
@TableField(exist = false)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params;
public Map<String, Object> getParams() {
if (params == null) {
params = new HashMap<>();
}
return params;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
}

View File

@@ -20,6 +20,8 @@ public interface AquPayOrderMapper extends BaseMapper<AquPayOrder> {
List<AquPayDevice> selectInfoByHour(Integer hour);
List<AquPayDevice> selectInfoForBackfill(Integer hour);
void updatePayDeviceStatus(@Param("list") List<AquPayDevice> list);
void dealRechargeWarnCode();

View File

@@ -24,6 +24,11 @@ public interface IAquPayOrderService extends IService<AquPayOrder> {
List<AquPayDevice> selectInfoByHour(Integer hour);
/**
* 补录用: 查询指定时间范围内所有订单(忽略profit_status)
*/
List<AquPayDevice> selectInfoForBackfill(Integer hour);
void updatePayDeviceStatus(List<AquPayDevice> list);
void dealRechargeWarnCode();

View File

@@ -46,6 +46,11 @@ public class AquPayOrderServiceImpl extends ServiceImpl<AquPayOrderMapper, AquPa
return aquPayOrderMapper.selectInfoByHour(hour);
}
@Override
public List<AquPayDevice> selectInfoForBackfill(Integer hour) {
return aquPayOrderMapper.selectInfoForBackfill(hour);
}
@Override
public void updatePayDeviceStatus(List<AquPayDevice> list) {
aquPayOrderMapper.updatePayDeviceStatus(list);

View File

@@ -3,9 +3,12 @@ package com.limap.core.basic.service.impl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.limap.common.utils.DateUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -18,6 +21,7 @@ import com.limap.core.basic.service.IBasicUserWithdrawService;
import com.limap.core.basic.vo.BasicUserWithdrawVo;
import com.limap.core.basic.vo.SharingRecordSearchVo;
import com.limap.core.basic.vo.SharingUserTaskVo;
import com.baomidou.dynamic.datasource.annotation.DS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -29,6 +33,8 @@ import com.limap.core.basic.mapper.BasicProfitSharingRecordMapper;
import com.limap.core.basic.domain.BasicProfitSharingRecord;
import com.limap.core.basic.service.IBasicProfitSharingRecordService;
import java.util.Collection;
/**
* 分润记录Service业务层处理
*
@@ -37,6 +43,7 @@ import com.limap.core.basic.service.IBasicProfitSharingRecordService;
*/
@Service
@Slf4j
@DS("master")
public class BasicProfitSharingRecordServiceImpl extends ServiceImpl<BasicProfitSharingRecordMapper, BasicProfitSharingRecord> implements IBasicProfitSharingRecordService {
@Autowired
private BasicProfitSharingRecordMapper basicProfitSharingRecordMapper;
@@ -82,16 +89,69 @@ public class BasicProfitSharingRecordServiceImpl extends ServiceImpl<BasicProfit
if (StringUtils.isNotNull(basicProfitSharingRecord.getDeviceName())) {
queryWrapper.eq(BasicProfitSharingRecord::getDeviceName, basicProfitSharingRecord.getDeviceName());
}
if (StringUtils.isNotNull(basicProfitSharingRecord.getStartTime())) {
// 兼容前端params[beginTime]/params[endTime]传参方式
Map<String, Object> params = basicProfitSharingRecord.getParams();
String scopeType = (String) params.get("scopeType");
Long scopeDeptId = (Long) params.get("scopeDeptId");
if (StringUtils.isNotNull(scopeDeptId)) {
if ("deptAndChild".equals(scopeType)) {
queryWrapper.inSql(BasicProfitSharingRecord::getDeptId,
"SELECT dept_id FROM sys_dept WHERE dept_id = " + scopeDeptId + " OR find_in_set(" + scopeDeptId + ", ancestors)");
} else if ("dept".equals(scopeType)) {
queryWrapper.eq(BasicProfitSharingRecord::getDeptId, scopeDeptId);
}
}
String beginTime = (String) params.get("beginTime");
String endTime = (String) params.get("endTime");
if (StringUtils.isNotEmpty(beginTime) && StringUtils.isNotEmpty(endTime)) {
queryWrapper.ge(BasicProfitSharingRecord::getGenerateTime, beginTime + " 00:00:00");
queryWrapper.le(BasicProfitSharingRecord::getGenerateTime, endTime + " 23:59:59");
} else if (StringUtils.isNotNull(basicProfitSharingRecord.getStartTime())) {
queryWrapper.between(BasicProfitSharingRecord::getGenerateTime, basicProfitSharingRecord.getStartTime(), basicProfitSharingRecord.getEndTime());
}
if (StringUtils.isNotNull(basicProfitSharingRecord.getTel())) {
queryWrapper.like(BasicProfitSharingRecord::getTel, basicProfitSharingRecord.getTel());
}
if (StringUtils.isNotEmpty(basicProfitSharingRecord.getUserName())) {
queryWrapper.like(BasicProfitSharingRecord::getUserName, basicProfitSharingRecord.getUserName());
}
if (StringUtils.isNotEmpty(basicProfitSharingRecord.getOrderNo())) {
queryWrapper.like(BasicProfitSharingRecord::getOrderNo, basicProfitSharingRecord.getOrderNo());
}
queryWrapper.orderByDesc(BasicProfitSharingRecord::getGenerateTime);
return basicProfitSharingRecordMapper.selectList(queryWrapper);
}
/**
* 重写saveBatch解决dynamic-datasource下批量插入事务不提交的问题
* 1. saveBatch内部BATCH模式绕过@DS
* 2. @Transactional与@DS冲突导致事务不提交
* 去掉@Transactional依赖连接池autoCommit=true逐条提交
*/
@DS("master")
@Override
public boolean saveBatch(Collection<BasicProfitSharingRecord> entityList, int batchSize) {
if (entityList == null || entityList.isEmpty()) {
return false;
}
log.info("saveBatch开始, 待插入{}条记录", entityList.size());
int count = 0;
for (BasicProfitSharingRecord record : entityList) {
try {
int rows = basicProfitSharingRecordMapper.insert(record);
if (rows > 0) {
count++;
} else {
log.warn("insert返回0行, record.orderNo={}, record.userId={}", record.getOrderNo(), record.getUserId());
}
} catch (Exception e) {
log.error("insert单条异常, record.orderNo={}, error={}", record.getOrderNo(), e.getMessage());
}
}
log.info("saveBatch完成, 预期插入{}条, 实际影响行数{}条", entityList.size(), count);
return count > 0;
}
/**
* 处理分润计算
*

View File

@@ -2,6 +2,9 @@ package com.limap.core.basic.vo;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class SharingRecordSearchVo {
@@ -10,4 +13,7 @@ public class SharingRecordSearchVo {
private Long userId;
private Long deptId;
/** 请求参数(前端传 params[startDate] 等) */
private Map<String, Object> params = new HashMap<>();
}

View File

@@ -21,9 +21,28 @@
<select id="selectInfoByHour" resultType="com.limap.core.basic.domain.AquPayDevice">
select * from aqu_pay_device
where create_time &gt;= now() - interval '${hour} hour'
AND create_time &lt;= now() - interval '1 hour'
AND (profit_status IS NULL OR profit_status = 0)
select apd.id, apd.user_id, apd.pay_amount, apd.pay_type, apd.create_time as "createdTime",
apd.device_type, apd.serial_num, apd.order_id, apd.profit_status
from aqu_pay_device apd
inner join aqu_pay_order apo on apo.id = apd.order_id
where apd.create_time &gt;= now() - interval '${hour} hour'
AND apd.create_time &lt;= now() - interval '1 hour'
AND (apd.profit_status IS NULL OR apd.profit_status = 0)
AND apd.pay_type = 1
AND apd.pay_amount &gt; 0
AND apo.order_status = 2
</select>
<!-- 补录用: 查询指定时间范围内支付成功订单(忽略profit_status) -->
<select id="selectInfoForBackfill" resultType="com.limap.core.basic.domain.AquPayDevice">
select apd.id, apd.user_id, apd.pay_amount, apd.pay_type, apd.create_time as "createdTime",
apd.device_type, apd.serial_num, apd.order_id, apd.profit_status
from aqu_pay_device apd
inner join aqu_pay_order apo on apo.id = apd.order_id
where apd.create_time &gt;= now() - interval '${hour} hour'
AND apd.create_time &lt;= now() - interval '1 hour'
AND apd.pay_type = 1
AND apd.pay_amount &gt; 0
AND apo.order_status = 2
</select>
</mapper>

View File

@@ -12,19 +12,27 @@
SUM(CASE WHEN withdrawal_status = 1 THEN amount ELSE 0 END) AS tx
FROM basic_profit_sharing_record
<where>
<if test="startDate != null">
AND created_time &gt;= #{startDate}
<if test="params.startDate != null and params.startDate != ''">
AND generate_time &gt;= #{params.startDate}
</if>
<if test="endDate != null">
AND created_time &lt;= #{endDate}
<if test="params.endDate != null and params.endDate != ''">
AND generate_time &lt;= #{params.endDate}
</if>
<if test="startDate != null and startDate != ''">
AND generate_time &gt;= #{startDate}
</if>
<if test="endDate != null and endDate != ''">
AND generate_time &lt;= #{endDate}
</if>
<if test="userId != null">
AND user_id = #{userId}
</if>
<if test="deptId != null">
and dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = #{deptId} or find_in_set( #{deptId} , ancestors ))
<if test="deptId != null and params.scopeType == 'dept'">
and dept_id = #{deptId}
</if>
<if test="deptId != null and (params.scopeType == null or params.scopeType == 'deptAndChild')">
and dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = #{deptId} or find_in_set( #{deptId} , ancestors ))
</if>
</where>
</select>
</mapper>

View File

@@ -21,7 +21,6 @@
FROM basic_profit_sharing_user bpsu
LEFT JOIN sys_user su ON bpsu.user_id = su.user_id
LEFT JOIN basic_user_bind_info bibi ON bpsu.user_id = bibi.user_id
WHERE bibi.device_name IS NOT NULL
</select>
<!-- 查询缓存用的分润用户列表 -->

View File

@@ -34,6 +34,6 @@
<if test="appUserTel != null and appUserTel != ''"> and app_user_tel = #{appUserTel}</if>
<if test="userName != null and userName != ''"> and user_name like CONCAT('%',#{userName},'%')</if>
</where>
order by create_time desc
</select>
</mapper>

View File

@@ -37,14 +37,27 @@ public class ProfitTask {
private IBasicUserBindInfoService basicUserBindInfoService;
public void execute(Integer hour) {
log.info("分润计算定时任务开始");
// TODO: 抽取支付订单,计算分润,更新分润表
log.info("=== 分润计算定时任务开始, hour={} ===", hour);
// 步骤1: 查询待处理订单
List<AquPayDevice> list = aquPayOrderService.selectInfoByHour(hour);
log.info("[步骤1] 查询到待处理订单数量: {}", list == null ? 0 : list.size());
if (list != null && list.size() > 0) {
// 打印前5条订单的设备序列号方便核对
list.stream().limit(5).forEach(o -> log.info("[步骤1-样本] 订单id={}, serialNum={}, payAmount={}, deviceType={}, profitStatus={}",
o.getId(), o.getSerialNum(), o.getPayAmount(), o.getDeviceType(), o.getProfitStatus()));
// 步骤2: 查询分润用户
List<SharingUserTaskVo> sharingUserTaskVos = sharingUserService.selectBasicInfoList();
log.info("[步骤2] 查询到分润用户数量: {}", sharingUserTaskVos == null ? 0 : sharingUserTaskVos.size());
if (sharingUserTaskVos != null && sharingUserTaskVos.size() > 0) {
sharingUserTaskVos.stream().limit(5).forEach(u -> log.info("[步骤2-样本] userId={}, deviceName={}, omRatio={}, controlRatio={}, type={}",
u.getUserId(), u.getDeviceName(), u.getOmRatio(), u.getControlRatio(), u.getType()));
}
boolean b = list.stream().anyMatch(e -> e.getDeviceType() == 2);
if (b) {
BasicProfitSharingUser byId = sharingUserService.getById(101);
log.info("[步骤2-控制柜] 存在deviceType=2的订单, id=101的分润用户: {}", byId != null ? "存在" : "不存在");
if (byId != null) {
list.stream().filter(e -> e.getDeviceType() == 2).forEach(e -> {
SharingUserTaskVo sharingUserTaskVo = new SharingUserTaskVo();
@@ -58,67 +71,229 @@ public class ProfitTask {
}
}
if (sharingUserTaskVos == null || sharingUserTaskVos.size() == 0) {
log.info("没有需要计算的用户");
log.info("[步骤2] 没有需要计算的用户,退出");
return;
}
// 步骤3: 按设备名分组
Map<String,List<SharingUserTaskVo>> collect = dealProfitUser(sharingUserTaskVos);
log.info("[步骤3] dealProfitUser后设备分组数量: {}, 设备名keys(前10): {}",
collect.size(), collect.keySet().stream().limit(10).collect(Collectors.joining(", ")));
// 步骤4: 匹配订单与分润用户
List<BasicProfitSharingRecord> basicProfitSharingRecords = new ArrayList<>();
List<AquPayDevice> aquPayOrders = new ArrayList<>();
list.forEach(aquPayOrder -> {
try{
int matchCount = 0;
int noMatchCount = 0;
List<String> noMatchDevices = new ArrayList<>();
for (AquPayDevice aquPayOrder : list) {
try {
String deviceName = aquPayOrder.getSerialNum();
if (collect.containsKey(deviceName)) {
matchCount++;
List<SharingUserTaskVo> sharingUserTaskVos1 = collect.get(deviceName);
sharingUserTaskVos1.forEach(sharingUserTaskVo -> {
// 计算分润
try{
for (SharingUserTaskVo sharingUserTaskVo : sharingUserTaskVos1) {
try {
BasicProfitSharingRecord basicProfitSharingRecord = basicProfitSharingRecordService.calculateProfit(aquPayOrder, sharingUserTaskVo);
basicProfitSharingRecords.add(basicProfitSharingRecord);
aquPayOrder.setProfitStatus(1);
aquPayOrders.add(aquPayOrder);
}catch (Exception e){
log.error("订单号:{},分润计算异常",aquPayOrder.getId(),e);
} catch (Exception e) {
log.error("[步骤4] 订单id={}serialNum={},分润计算异常: {}", aquPayOrder.getId(), aquPayOrder.getSerialNum(), e.getMessage(), e);
}
});
}
} else {
noMatchCount++;
if (noMatchDevices.size() < 10) {
noMatchDevices.add(deviceName);
}
}
}catch (Exception e){
log.error("订单号:{}jsonDeviceSerialNum解析异常",aquPayOrder.getId(),e);
} catch (Exception e) {
log.error("[步骤4] 订单id={},处理异常: {}", aquPayOrder.getId(), e.getMessage(), e);
}
});
// 批量更新订单状态和分润表
if (basicProfitSharingRecords.size() > 0) {
basicProfitSharingRecordService.saveBatch(basicProfitSharingRecords);
aquPayOrderService.updatePayDeviceStatus(aquPayOrders);
}
}else{
log.info("没有需要计算的订单");
log.info("[步骤4] 匹配成功: {}条, 未匹配: {}条, 生成分润记录: {}条", matchCount, noMatchCount, basicProfitSharingRecords.size());
if (noMatchDevices.size() > 0) {
log.info("[步骤4] 未匹配的设备名(前10): {}", String.join(", ", noMatchDevices));
}
// 步骤5: 批量保存
if (basicProfitSharingRecords.size() > 0) {
log.info("[步骤5] 准备批量保存分润记录: {}条, 更新订单状态: {}条", basicProfitSharingRecords.size(), aquPayOrders.size());
try {
// 保存前查询记录数
long beforeCount = basicProfitSharingRecordService.count();
log.info("[步骤5] 保存前表中记录数: {}", beforeCount);
basicProfitSharingRecordService.saveBatch(basicProfitSharingRecords);
// 保存后立即查询验证
long afterCount = basicProfitSharingRecordService.count();
log.info("[步骤5] 保存后表中记录数: {}, 新增: {}", afterCount, afterCount - beforeCount);
if (afterCount > beforeCount) {
aquPayOrderService.updatePayDeviceStatus(aquPayOrders);
log.info("[步骤5] 批量保存成功, 实际新增{}条", afterCount - beforeCount);
} else {
log.error("[步骤5] 严重问题: saveBatch执行完毕但表中无新增数据! 可能是数据源路由问题");
}
} catch (Exception e) {
log.error("[步骤5] 批量保存异常: {}", e.getMessage(), e);
}
} else {
log.info("[步骤5] 没有生成任何分润记录,跳过保存");
}
} else {
log.info("[步骤1] 没有需要计算的订单(hour={})", hour);
}
log.info("分润计算定时任务结束");
log.info("=== 分润计算定时任务结束 ===");
}
/**
* 补录历史分润数据
* 从4月8日至今约1300小时调用方式: profitTask.backfill()
* 或指定小时数: profitTask.backfillByHours(1300)
* 注意: 此方法会忽略profit_status查询所有订单并通过order_no去重避免重复写入
*/
public void backfill() {
backfillByHours(1500);
}
public void backfillByHours(Integer hours) {
log.info("===== 开始补录历史分润数据, 回溯{}小时 =====", hours);
// 使用backfill专用查询忽略profit_status
List<AquPayDevice> list = aquPayOrderService.selectInfoForBackfill(hours);
log.info("[补录] 查询到订单数量: {}", list == null ? 0 : list.size());
if (list == null || list.isEmpty()) {
log.info("[补录] 没有需要补录的订单");
return;
}
// 查询已存在的分润记录order_no用于去重
List<BasicProfitSharingRecord> existingRecords = basicProfitSharingRecordService.list();
Set<String> existingOrderNos = existingRecords.stream()
.map(BasicProfitSharingRecord::getOrderNo)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
log.info("[补录] 已存在分润记录数: {}", existingOrderNos.size());
// 过滤掉已有记录的订单
List<AquPayDevice> needProcessList = list.stream()
.filter(o -> !existingOrderNos.contains(String.valueOf(o.getOrderId())))
.collect(Collectors.toList());
log.info("[补录] 去重后需要处理的订单数: {}", needProcessList.size());
if (needProcessList.isEmpty()) {
log.info("[补录] 所有订单均已有分润记录,无需补录");
return;
}
// 查询分润用户
List<SharingUserTaskVo> sharingUserTaskVos = sharingUserService.selectBasicInfoList();
log.info("[补录] 分润用户数量: {}", sharingUserTaskVos == null ? 0 : sharingUserTaskVos.size());
// 处理deviceType=2的控制柜订单
boolean hasControlDevice = needProcessList.stream().anyMatch(e -> e.getDeviceType() == 2);
if (hasControlDevice) {
BasicProfitSharingUser byId = sharingUserService.getById(101);
if (byId != null) {
needProcessList.stream().filter(e -> e.getDeviceType() == 2).forEach(e -> {
SharingUserTaskVo vo = new SharingUserTaskVo();
vo.setDeviceName(e.getSerialNum());
vo.setUserId(byId.getUserId());
vo.setControlRatio(byId.getControlRatio());
vo.setOmRatio(byId.getOmRatio());
vo.setType("2");
sharingUserTaskVos.add(vo);
});
}
}
if (sharingUserTaskVos == null || sharingUserTaskVos.isEmpty()) {
log.info("[补录] 没有分润用户,退出");
return;
}
Map<String, List<SharingUserTaskVo>> collect = dealProfitUser(sharingUserTaskVos);
List<BasicProfitSharingRecord> records = new ArrayList<>();
for (AquPayDevice order : needProcessList) {
try {
String deviceName = order.getSerialNum();
if (collect.containsKey(deviceName)) {
for (SharingUserTaskVo vo : collect.get(deviceName)) {
try {
BasicProfitSharingRecord record = basicProfitSharingRecordService.calculateProfit(order, vo);
records.add(record);
} catch (Exception e) {
log.error("[补录] 订单id={}, 计算异常: {}", order.getId(), e.getMessage());
}
}
}
} catch (Exception e) {
log.error("[补录] 订单id={}, 处理异常: {}", order.getId(), e.getMessage());
}
}
log.info("[补录] 生成分润记录: {}条", records.size());
if (!records.isEmpty()) {
try {
basicProfitSharingRecordService.saveBatch(records);
log.info("[补录] 保存成功, 共{}条记录", records.size());
} catch (Exception e) {
log.error("[补录] 保存异常: {}", e.getMessage(), e);
}
}
log.info("===== 补录历史分润数据完成 =====");
}
public void executeEquipmentBind() {
List<BasicUserBindInfo> deviceId = basicUserBindInfoService.list(
new LambdaQueryWrapper<BasicUserBindInfo>().isNull(BasicUserBindInfo::getDeviceId)
// 查询需要补全的记录device_id为空 或 app_user为空小程序用户后绑定的情况
List<BasicUserBindInfo> needUpdateList = basicUserBindInfoService.list(
new LambdaQueryWrapper<BasicUserBindInfo>()
.and(w -> w.isNull(BasicUserBindInfo::getDeviceId)
.or().isNull(BasicUserBindInfo::getAppUser))
);
if (!CollectionUtils.isEmpty(deviceId)) {
List<BasicUserBindInfo> appUserInfo = basicUserBindInfoService.selectAppUserInfo();
if(!CollectionUtils.isEmpty(appUserInfo)){
Map<String, List<BasicUserBindInfo>> collect = appUserInfo.stream().collect(Collectors.groupingBy(BasicUserBindInfo::getDeviceName));
List<BasicUserBindInfo> updateList = new ArrayList<>();
deviceId.forEach(e -> {
if (collect.containsKey(e.getDeviceName())) {
List<BasicUserBindInfo> list = collect.get(e.getDeviceName());
BasicUserBindInfo e1 = list.get(0);
e1.setId(e.getId());
updateList.add(e1);
}
});
if (updateList.size() > 0) {
basicUserBindInfoService.updateBatchById(updateList);
}
if (CollectionUtils.isEmpty(needUpdateList)) {
log.info("没有需要补全的设备绑定记录");
return;
}
log.info("[设备绑定补全] 待处理记录数: {}", needUpdateList.size());
// 从aqu_device + aqu_user获取最新设备和用户信息
List<BasicUserBindInfo> appUserInfo = basicUserBindInfoService.selectAppUserInfo();
if (CollectionUtils.isEmpty(appUserInfo)) {
log.info("[设备绑定补全] aqu_device中无设备数据");
return;
}
Map<String, List<BasicUserBindInfo>> collect = appUserInfo.stream()
.filter(e -> e != null && e.getDeviceName() != null)
.collect(Collectors.groupingBy(BasicUserBindInfo::getDeviceName));
List<BasicUserBindInfo> updateList = new ArrayList<>();
for (BasicUserBindInfo record : needUpdateList) {
if (collect.containsKey(record.getDeviceName())) {
BasicUserBindInfo source = collect.get(record.getDeviceName()).get(0);
// 创建新对象避免对象引用问题
BasicUserBindInfo updateItem = new BasicUserBindInfo();
updateItem.setId(record.getId());
updateItem.setDeviceId(source.getDeviceId());
updateItem.setIotId(source.getIotId());
updateItem.setType(source.getType());
updateItem.setBindTime(source.getBindTime());
updateItem.setAppUser(source.getAppUser());
updateItem.setAppUserName(source.getAppUserName());
updateItem.setAppUserTel(source.getAppUserTel());
updateList.add(updateItem);
}
}else{
log.info("没有需要绑定的设备");
}
if (updateList.size() > 0) {
basicUserBindInfoService.updateBatchById(updateList);
log.info("[设备绑定补全] 成功更新{}条记录", updateList.size());
} else {
log.info("[设备绑定补全] 没有匹配到aqu_device中的设备");
}
}
@@ -129,7 +304,7 @@ public class ProfitTask {
Map<String, List<SharingUserTaskVo>> result = new HashMap<>();
collect.forEach((k, v) -> {
List<SharingUserTaskVo> distinctList = v.stream().distinct().collect(Collectors.toList());
List<SharingUserTaskVo> distinctList = distinctByUserId(v);
List<SharingUserTaskVo> newList = new ArrayList<>();
for (SharingUserTaskVo e : distinctList) {
if (e != null && e.getParentId() != null) {
@@ -138,7 +313,7 @@ public class ProfitTask {
newList.add(e);
}
}
result.put(k, newList.stream().distinct().collect(Collectors.toList()));
result.put(k, distinctByUserId(newList));
});
return result;
@@ -150,8 +325,8 @@ public class ProfitTask {
// 预处理数据,提高查找效率
Map<Long, SharingUserTaskVo> userTaskMap = sharingUserTaskVos.stream()
.filter(f -> f != null && f.getDeptId() != null)
.collect(Collectors.toMap(SharingUserTaskVo::getDeptId, f -> f, (existing, replacement) -> existing));
.filter(f -> f != null && f.getUserId() != null)
.collect(Collectors.toMap(SharingUserTaskVo::getUserId, f -> f, (existing, replacement) -> existing));
Set<Long> visited = new HashSet<>(); // 防止循环引用导致的无限循环
@@ -179,4 +354,19 @@ public class ProfitTask {
return resultList;
}
private List<SharingUserTaskVo> distinctByUserId(List<SharingUserTaskVo> list) {
Map<Long, SharingUserTaskVo> map = new LinkedHashMap<>();
for (SharingUserTaskVo item : list) {
if (item == null) {
continue;
}
Long userId = item.getUserId();
if (userId == null) {
continue;
}
map.putIfAbsent(userId, item);
}
return new ArrayList<>(map.values());
}
}