|
@@ -9,13 +9,18 @@ import java.time.LocalDateTime;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.ExecutionException;
|
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.function.Function;
|
|
import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
|
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
|
|
|
|
+import cn.hutool.core.bean.BeanUtil;
|
|
|
|
|
+import cn.hutool.core.util.IdUtil;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
import cn.hutool.json.JSONUtil;
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.fs.common.constant.HttpStatus;
|
|
import com.fs.common.constant.HttpStatus;
|
|
@@ -58,13 +63,11 @@ import com.fs.his.domain.FsUserIntegralLogs;
|
|
|
import com.fs.his.dto.FindUsersByDTO;
|
|
import com.fs.his.dto.FindUsersByDTO;
|
|
|
import com.fs.his.enums.FsUserIntegralLogTypeEnum;
|
|
import com.fs.his.enums.FsUserIntegralLogTypeEnum;
|
|
|
import com.fs.his.mapper.*;
|
|
import com.fs.his.mapper.*;
|
|
|
-import com.fs.his.param.FindUserByParam;
|
|
|
|
|
-import com.fs.his.param.FsUserAddIntegralTemplateParam;
|
|
|
|
|
-import com.fs.his.param.FsUserParam;
|
|
|
|
|
-import com.fs.his.service.IFsUserIntegralLogsService;
|
|
|
|
|
-import com.fs.his.service.IFsUserProjectTagService;
|
|
|
|
|
-import com.fs.his.service.IFsUserWxService;
|
|
|
|
|
|
|
+import com.fs.his.param.*;
|
|
|
|
|
+import com.fs.his.service.*;
|
|
|
import com.fs.his.utils.PhoneUtil;
|
|
import com.fs.his.utils.PhoneUtil;
|
|
|
|
|
+import com.fs.his.utils.ProfitShareUtils;
|
|
|
|
|
+import com.fs.his.utils.UniAdSignUtils;
|
|
|
import com.fs.his.vo.*;
|
|
import com.fs.his.vo.*;
|
|
|
import com.fs.im.config.ImTypeConfig;
|
|
import com.fs.im.config.ImTypeConfig;
|
|
|
import com.fs.im.service.OpenIMService;
|
|
import com.fs.im.service.OpenIMService;
|
|
@@ -94,8 +97,10 @@ import com.fs.system.service.ISysConfigService;
|
|
|
import com.fs.watch.domain.WatchUser;
|
|
import com.fs.watch.domain.WatchUser;
|
|
|
import com.fs.watch.domain.vo.FsUserAndCompanyAndDoctorVo;
|
|
import com.fs.watch.domain.vo.FsUserAndCompanyAndDoctorVo;
|
|
|
import com.fs.watch.service.WatchUserService;
|
|
import com.fs.watch.service.WatchUserService;
|
|
|
|
|
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
|
|
|
import com.github.pagehelper.PageHelper;
|
|
import com.github.pagehelper.PageHelper;
|
|
|
import com.github.pagehelper.PageInfo;
|
|
import com.github.pagehelper.PageInfo;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
import org.apache.http.client.ClientProtocolException;
|
|
import org.apache.http.client.ClientProtocolException;
|
|
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
@@ -105,12 +110,13 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
|
|
import org.apache.http.impl.client.HttpClients;
|
|
import org.apache.http.impl.client.HttpClients;
|
|
|
import org.apache.http.util.Asserts;
|
|
import org.apache.http.util.Asserts;
|
|
|
import org.apache.http.util.EntityUtils;
|
|
import org.apache.http.util.EntityUtils;
|
|
|
|
|
+import org.redisson.api.RLock;
|
|
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
-import com.fs.his.service.IFsUserService;
|
|
|
|
|
import org.springframework.transaction.annotation.Propagation;
|
|
import org.springframework.transaction.annotation.Propagation;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
@@ -124,6 +130,7 @@ import static com.fs.hisStore.enums.BillDetailEnum.CATEGORY_3;
|
|
|
* @author fs
|
|
* @author fs
|
|
|
* @date 2023-06-07
|
|
* @date 2023-06-07
|
|
|
*/
|
|
*/
|
|
|
|
|
+@Slf4j
|
|
|
@Service
|
|
@Service
|
|
|
public class FsUserServiceImpl implements IFsUserService {
|
|
public class FsUserServiceImpl implements IFsUserService {
|
|
|
Logger logger = LoggerFactory.getLogger(getClass());
|
|
Logger logger = LoggerFactory.getLogger(getClass());
|
|
@@ -173,14 +180,6 @@ public class FsUserServiceImpl implements IFsUserService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private IFsUserCompanyUserService userCompanyUserService;
|
|
private IFsUserCompanyUserService userCompanyUserService;
|
|
|
@Autowired
|
|
@Autowired
|
|
|
- private IQwExternalContactCacheService qwExternalContactCacheService;
|
|
|
|
|
-
|
|
|
|
|
- @Autowired
|
|
|
|
|
- private CompanyRoleMapper companyRoleMapper;
|
|
|
|
|
-
|
|
|
|
|
- @Autowired
|
|
|
|
|
- private RedisCache redisCache;
|
|
|
|
|
- @Autowired
|
|
|
|
|
private IFsUserProjectTagService userProjectTagService;
|
|
private IFsUserProjectTagService userProjectTagService;
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
@@ -207,6 +206,20 @@ public class FsUserServiceImpl implements IFsUserService {
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private CompanyUserUserMapper companyUserUserMapper;
|
|
private CompanyUserUserMapper companyUserUserMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private AdProfitDetailMapper adProfitDetailMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IFsIntegralExchangeService fsIntegralExchangeService;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IFsUserIntegralLogsService fsUserIntegralLogsService;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsUserIntegralLogsMapper fsUserIntegralLogsMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsIntegralRedPacketLogMapper integralRedPacketLogMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IFsStorePaymentService paymentService;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private RedissonClient redissonClient;
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -2053,4 +2066,391 @@ public class FsUserServiceImpl implements IFsUserService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 接收 UniApp 激励广告回调
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R uniCallBack(Map<String, Object> params) {
|
|
|
|
|
+ log.info("接收到uniapp激励广告回调参数:{}", params);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 交易id
|
|
|
|
|
+ String transId = params.get("trans_id").toString();
|
|
|
|
|
+ String sign = params.get("sign").toString();
|
|
|
|
|
+
|
|
|
|
|
+ // 签名验证
|
|
|
|
|
+ if (!UniAdSignUtils.verifySign(transId, sign)) {
|
|
|
|
|
+ log.error("签名验证失败:trans_id={}, sign={}", transId, sign);
|
|
|
|
|
+ return R.ok().put("isValid", false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 防止重复回调
|
|
|
|
|
+ int count = adProfitDetailMapper.selectCount(new LambdaQueryWrapper<AdProfitDetail>().eq(AdProfitDetail::getAdTransId, transId));
|
|
|
|
|
+ if (count > 0) {
|
|
|
|
|
+ return R.ok().put("isValid", false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!params.containsKey("cpm")){
|
|
|
|
|
+ AdProfitDetail adProfitDetail = new AdProfitDetail();
|
|
|
|
|
+ adProfitDetail.setAdTransId(transId);
|
|
|
|
|
+ adProfitDetail.setAdTaskId(params.get("extra").toString());
|
|
|
|
|
+ adProfitDetail.setUserId(Long.valueOf(params.get("user_id").toString()));
|
|
|
|
|
+ adProfitDetail.setCreateTime(LocalDateTime.now());
|
|
|
|
|
+ adProfitDetail.setOriginParam(JSON.toJSONString(params));
|
|
|
|
|
+ int result = adProfitDetailMapper.insert(adProfitDetail);
|
|
|
|
|
+ log.error("uniapp广告回调cpm为空,回调参数={}", params);
|
|
|
|
|
+ return R.ok().put("isValid", false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 广告收益(元)
|
|
|
|
|
+ BigDecimal singleProfit = new BigDecimal(params.get("cpm").toString())
|
|
|
|
|
+ .divide(new BigDecimal("1000"), 6, RoundingMode.HALF_UP);
|
|
|
|
|
+
|
|
|
|
|
+ // 获取分润比例
|
|
|
|
|
+ String json = configService.selectConfigByKey("his.integral");
|
|
|
|
|
+ IntegralConfig config = JSONUtil.toBean(json, IntegralConfig.class);
|
|
|
|
|
+
|
|
|
|
|
+ List<BigDecimal> ratios = Arrays.asList(
|
|
|
|
|
+ config.getIntegralUserRatio(),
|
|
|
|
|
+ config.getIntegralCompanyRatio(),
|
|
|
|
|
+ config.getIntegralHuYiRatio(),
|
|
|
|
|
+ config.getIntegralYunLianRatio()
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 使用银行级分配算法
|
|
|
|
|
+ Map<Integer, BigDecimal> profitMap = ProfitShareUtils.allocate(singleProfit, ratios);
|
|
|
|
|
+
|
|
|
|
|
+ BigDecimal customerProfit = profitMap.get(0);
|
|
|
|
|
+ BigDecimal salesProfit = profitMap.get(1);
|
|
|
|
|
+ BigDecimal huyiProfit = profitMap.get(2);
|
|
|
|
|
+ BigDecimal yunlianProfit = profitMap.get(3);
|
|
|
|
|
+
|
|
|
|
|
+ // 计算用户本次广告积分
|
|
|
|
|
+ BigDecimal userIntegra = customerProfit.multiply(new BigDecimal("10")).setScale(0, RoundingMode.DOWN);
|
|
|
|
|
+ // 配置的保底收益
|
|
|
|
|
+ Integer minimumIntegral = config.getMinimumIntegral();
|
|
|
|
|
+ boolean resultCom = userIntegra.compareTo(BigDecimal.valueOf(minimumIntegral)) < 0;
|
|
|
|
|
+
|
|
|
|
|
+ // 查询用户的销售公司
|
|
|
|
|
+ String companyId = adProfitDetailMapper.getCompanyByUserId(params.get("user_id").toString());
|
|
|
|
|
+
|
|
|
|
|
+ // 入库
|
|
|
|
|
+ AdProfitDetail adProfitDetail = new AdProfitDetail();
|
|
|
|
|
+ adProfitDetail.setAdTransId(transId);
|
|
|
|
|
+ adProfitDetail.setAdTaskId(params.get("extra").toString());
|
|
|
|
|
+ adProfitDetail.setSumMoney(singleProfit);
|
|
|
|
|
+ adProfitDetail.setUserId(Long.valueOf(params.get("user_id").toString()));
|
|
|
|
|
+ // 如果用户收益小于保底收益,直接给用户保底 并且不进行分润
|
|
|
|
|
+ if (resultCom) {
|
|
|
|
|
+ adProfitDetail.setUserMoney(BigDecimal.valueOf(minimumIntegral).divide(new BigDecimal("10"),2,RoundingMode.DOWN));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ adProfitDetail.setUserMoney(customerProfit);
|
|
|
|
|
+ adProfitDetail.setCompanyMoney(salesProfit);
|
|
|
|
|
+ adProfitDetail.setHuyiMoney(huyiProfit);
|
|
|
|
|
+ adProfitDetail.setYunlianMoney(yunlianProfit);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ adProfitDetail.setCompanyId(
|
|
|
|
|
+ StringUtils.isNotEmpty(companyId) ? Long.valueOf(companyId) : null
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ adProfitDetail.setCreateTime(LocalDateTime.now());
|
|
|
|
|
+ adProfitDetail.setOriginParam(JSON.toJSONString(params));
|
|
|
|
|
+
|
|
|
|
|
+ int result = adProfitDetailMapper.insert(adProfitDetail);
|
|
|
|
|
+
|
|
|
|
|
+ return R.ok().put("isValid", result > 0);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error(
|
|
|
|
|
+ "【广告回调 异常】,原始参数={}", params, e);
|
|
|
|
|
+ return R.ok().put("isValid", false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * uniapp广告 返回一个广告id
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R createLogs(Long userId) {
|
|
|
|
|
+ String adTaskId = IdUtil.fastSimpleUUID() + userId;
|
|
|
|
|
+ return R.ok().put("extra", adTaskId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取用户钱包明细
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R getWallet(Long userId) {
|
|
|
|
|
+ IntegralExchangeVo vo = fsUserMapper.getWallet(userId);
|
|
|
|
|
+ vo.setMayWithdraw(vo.getMayWithdraw().divide(BigDecimal.valueOf(100)));
|
|
|
|
|
+ vo.setTotalCommission(vo.getTotalCommission().divide(BigDecimal.valueOf(100)));
|
|
|
|
|
+ vo.setWithdrawFinish(vo.getWithdrawFinish().divide(BigDecimal.valueOf(100)));
|
|
|
|
|
+ vo.setWithdrawCash(new BigDecimal(vo.getWithdrawIntegral()).divide(BigDecimal.valueOf(1000),2,RoundingMode.DOWN));
|
|
|
|
|
+ return R.ok().put("data", vo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 用户钱包 积分兑换佣金
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R integralExchange(Long userId) {
|
|
|
|
|
+ // 查询用户钱包明细
|
|
|
|
|
+ FsUser fsUser = fsUserMapper.selectFsUserByUserId(userId);
|
|
|
|
|
+ if (BeanUtil.isEmpty(fsUser)) {
|
|
|
|
|
+ return R.error("用户不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Long withdrawIntegral = fsUser.getWithdrawIntegral();
|
|
|
|
|
+ if (withdrawIntegral <= 0){
|
|
|
|
|
+ return R.error("积分不足");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 积分转金额 1元=1000积分 库里存储的是单位是分:÷10
|
|
|
|
|
+ BigDecimal commission = new BigDecimal(withdrawIntegral ).divide(BigDecimal.valueOf(10),2,RoundingMode.DOWN);
|
|
|
|
|
+ // 更新用户积分 佣金
|
|
|
|
|
+ FsUser user = new FsUser();
|
|
|
|
|
+ user.setUserId(userId);
|
|
|
|
|
+ user.setIntegral(fsUser.getIntegral() - withdrawIntegral);
|
|
|
|
|
+ user.setWithdrawIntegral(0L);
|
|
|
|
|
+ user.setTotalCommission(fsUser.getTotalCommission().add(commission));
|
|
|
|
|
+ user.setUpdateTime(new Date());
|
|
|
|
|
+ user.setMayWithdraw(fsUser.getMayWithdraw().add(commission));
|
|
|
|
|
+ fsUserMapper.updateFsUser(user);
|
|
|
|
|
+ FsIntegralExchange fsIntegralExchange = new FsIntegralExchange();
|
|
|
|
|
+ fsIntegralExchange.setUserId(userId);
|
|
|
|
|
+ fsIntegralExchange.setNickName(fsUser.getNickName());
|
|
|
|
|
+ fsIntegralExchange.setPhone(fsUser.getPhone());
|
|
|
|
|
+ fsIntegralExchange.setCreateTime(new Date());
|
|
|
|
|
+ fsIntegralExchange.setIntegral(-withdrawIntegral);
|
|
|
|
|
+ fsIntegralExchangeService.insertFsIntegralExchange(fsIntegralExchange);
|
|
|
|
|
+ //添加积分记录
|
|
|
|
|
+ FsUserIntegralLogs logs = new FsUserIntegralLogs();
|
|
|
|
|
+ logs.setUserId(userId);
|
|
|
|
|
+ if(fsIntegralExchange.getId() != null){
|
|
|
|
|
+ logs.setBusinessId(fsIntegralExchange.getId().toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ logs.setLogType(FsUserIntegralLogTypeEnum.TYPE_32.getValue());
|
|
|
|
|
+ logs.setIntegral(-withdrawIntegral);
|
|
|
|
|
+ logs.setBalance(fsUser.getIntegral() - withdrawIntegral);
|
|
|
|
|
+ logs.setCreateTime(new Date());
|
|
|
|
|
+ logs.setNickName(StringUtils.isNotEmpty(fsUser.getNickName()) ? fsUser.getNickName() : null);
|
|
|
|
|
+ logs.setPhone(fsUser.getPhone());
|
|
|
|
|
+ fsUserIntegralLogsService.insertFsUserIntegralLogs(logs);
|
|
|
|
|
+ return R.ok("兑换成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 用户钱包 获取兑换明细
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R exchangDetail(Map<String, Object> params) {
|
|
|
|
|
+ PageHelper.startPage(Integer.parseInt(params.get("page").toString()), Integer.parseInt(params.get("limit").toString()));
|
|
|
|
|
+ ExchangeDetailVo detailVo = new ExchangeDetailVo();
|
|
|
|
|
+ detailVo.setUserId(Long.valueOf(params.get("userId").toString()));
|
|
|
|
|
+ detailVo.setLogType(FsUserIntegralLogTypeEnum.TYPE_32.getValue());
|
|
|
|
|
+ // 查询积分记录
|
|
|
|
|
+ List<ExchangeDetailVo> logsList =fsUserIntegralLogsMapper.getExchangDetailList(detailVo);
|
|
|
|
|
+ PageInfo<ExchangeDetailVo> logsPageInfo = new PageInfo<>(logsList);
|
|
|
|
|
+ Map<String,Object> rMap = new HashMap<>();
|
|
|
|
|
+ rMap.put("rows", logsPageInfo.getList());
|
|
|
|
|
+ rMap.put("total", logsPageInfo.getTotal());
|
|
|
|
|
+ return R.ok().put("data", rMap);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 用户提现
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R withdrawal(FsIntegralWithdrawalParam param) {
|
|
|
|
|
+ Long userId = param.getUserId();
|
|
|
|
|
+ // 生成锁的key,基于用户ID和视频ID确保同一用户同一视频的请求被锁定
|
|
|
|
|
+ String lockKey = "reward_integral_lock:user:" + userId;
|
|
|
|
|
+ RLock lock = redissonClient.getLock(lockKey);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 尝试获取锁,等待时间5秒,锁过期时间30秒
|
|
|
|
|
+ boolean isLocked = lock.tryLock(5, 300, TimeUnit.SECONDS);
|
|
|
|
|
+ if (!isLocked) {
|
|
|
|
|
+ logger.warn("获取锁失败,用户ID:{}", userId);
|
|
|
|
|
+ return R.error("操作频繁,请稍后再试!");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ logger.info("成功获取锁,开始处理奖励发放,用户ID:{}", userId);
|
|
|
|
|
+ return executeWithdrawal(param);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ logger.error("获取锁被中断,用户ID:{}", userId, e);
|
|
|
|
|
+ return R.error("系统繁忙,请重试!");
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ // 释放锁
|
|
|
|
|
+ if (lock.isHeldByCurrentThread()) {
|
|
|
|
|
+ lock.unlock();
|
|
|
|
|
+ logger.info("释放锁成功,用户ID:{}", userId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private R executeWithdrawal(FsIntegralWithdrawalParam param){
|
|
|
|
|
+ //查询可提现
|
|
|
|
|
+ Long userId = param.getUserId();
|
|
|
|
|
+ FsUser fsUser = selectFsUserByUserId(userId);
|
|
|
|
|
+ if (fsUser == null) {
|
|
|
|
|
+ return R.error("用户不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ //拉黑用户不能提现
|
|
|
|
|
+ if (fsUser.getStatus() == 0){
|
|
|
|
|
+ return R.error("暂无法提现!");
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal mayWithdraw = fsUser.getMayWithdraw();
|
|
|
|
|
+ if (mayWithdraw == null || mayWithdraw.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
|
|
+ return R.error("用户无可提现金额");
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal applicationAmount = param.getApplicationAmount();
|
|
|
|
|
+ if (applicationAmount == null || applicationAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
|
|
+ return R.error("用户提现金额错误");
|
|
|
|
|
+ }
|
|
|
|
|
+ String json = configService.selectConfigByKey("his.integral");
|
|
|
|
|
+ IntegralConfig config = JSONUtil.toBean(json, IntegralConfig.class);
|
|
|
|
|
+ BigDecimal maxApplicationAmount = config.getMaxApplicationAmount();
|
|
|
|
|
+ if (maxApplicationAmount != null && maxApplicationAmount.compareTo(BigDecimal.ZERO) > 0 && applicationAmount.compareTo(maxApplicationAmount) > 0) {
|
|
|
|
|
+ return R.error("一次最多提现 "+ maxApplicationAmount + " 元");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (mayWithdraw.compareTo(applicationAmount.multiply(BigDecimal.valueOf(100))) < 0) {
|
|
|
|
|
+ return R.error("用户可提现金额不足");
|
|
|
|
|
+ }
|
|
|
|
|
+ Integer withdrawNum = config.getWithdrawNum();
|
|
|
|
|
+ if (withdrawNum != null) {
|
|
|
|
|
+ Long count = integralRedPacketLogMapper.countLogsByToday(userId);
|
|
|
|
|
+ if (count != null && count >= withdrawNum) {
|
|
|
|
|
+ return R.error("当天最多领取 " + withdrawNum + "次 ,未领取成功的,可点击详情重新领取!");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 保存log
|
|
|
|
|
+ FsIntegralRedPacketLog fsIntegralRedPacketLog = saveRedPacketLog(userId, applicationAmount,param.getAppId());
|
|
|
|
|
+ //来源是小程序切换openId
|
|
|
|
|
+ WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
|
|
|
|
|
+ String openId = getOpenId(param, fsUser);
|
|
|
|
|
+ if (StringUtils.isBlank(openId)) {
|
|
|
|
|
+ fsIntegralRedPacketLog.setStatus("-1");
|
|
|
|
|
+ fsIntegralRedPacketLog.setRemark("失败原因:未使用微信登录");
|
|
|
|
|
+ fsIntegralRedPacketLog.setReturnedStatus(1);
|
|
|
|
|
+ integralRedPacketLogMapper.updateFsIntegralRedPacketLog(fsIntegralRedPacketLog);
|
|
|
|
|
+ return R.error("请重新使用微信登录");
|
|
|
|
|
+ }
|
|
|
|
|
+ packetParam.setOpenId(openId);
|
|
|
|
|
+ packetParam.setAmount(applicationAmount);
|
|
|
|
|
+ packetParam.setSource(param.getSource());
|
|
|
|
|
+ packetParam.setAppId(param.getAppId());
|
|
|
|
|
+ try {
|
|
|
|
|
+ //发送红包
|
|
|
|
|
+ R sendRedPacket = paymentService.sendIntegralRedPacket(packetParam);
|
|
|
|
|
+
|
|
|
|
|
+ if (sendRedPacket.get("code").equals(200)) {
|
|
|
|
|
+ TransferBillsResult transferBillsResult;
|
|
|
|
|
+ if (sendRedPacket.get("isNew").equals(1)) {
|
|
|
|
|
+ transferBillsResult = (TransferBillsResult) sendRedPacket.get("data");
|
|
|
|
|
+ fsIntegralRedPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
|
|
|
|
|
+ fsIntegralRedPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fsIntegralRedPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
|
|
|
|
|
+ fsIntegralRedPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ fsIntegralRedPacketLog.setUpdateTime(new Date());
|
|
|
|
|
+ Object aPackage = sendRedPacket.get("package");
|
|
|
|
|
+ if (aPackage != null) {
|
|
|
|
|
+ fsIntegralRedPacketLog.setPackageInfo(aPackage.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ Object mchIdObj = sendRedPacket.get("mchId");
|
|
|
|
|
+ if (mchIdObj != null) {
|
|
|
|
|
+ fsIntegralRedPacketLog.setMchId(mchIdObj.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ // 更新观看记录的奖励类型
|
|
|
|
|
+ integralRedPacketLogMapper.updateFsIntegralRedPacketLog(fsIntegralRedPacketLog);
|
|
|
|
|
+ //减少可兑换佣金
|
|
|
|
|
+ BigDecimal fenWithdraw = fsIntegralRedPacketLog.getAmount().multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
|
|
|
|
|
+ mayWithdraw = mayWithdraw.subtract(fenWithdraw);
|
|
|
|
|
+ BigDecimal withdrawFinish = fsUser.getWithdrawFinish().add(fenWithdraw);
|
|
|
|
|
+ fsUser.setMayWithdraw(mayWithdraw);
|
|
|
|
|
+ fsUser.setWithdrawFinish(withdrawFinish);
|
|
|
|
|
+ log.info("佣金提现修改mayWithdraw:{},withdrawFinish:{}", mayWithdraw, fsUser.getWithdrawFinish());
|
|
|
|
|
+ fsUserMapper.updateFsUser(fsUser);
|
|
|
|
|
+ return sendRedPacket;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return R.error("提现失败!请联系管理员!" + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ return R.ok("发放成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private FsIntegralRedPacketLog saveRedPacketLog(Long userId, BigDecimal applicationAmount,String appId) {
|
|
|
|
|
+ FsIntegralRedPacketLog redPacketLog = new FsIntegralRedPacketLog();
|
|
|
|
|
+ redPacketLog.setUserId(userId);
|
|
|
|
|
+ redPacketLog.setAmount(applicationAmount);
|
|
|
|
|
+ redPacketLog.setStatus("0");
|
|
|
|
|
+ redPacketLog.setAppId(appId);
|
|
|
|
|
+ redPacketLog.setCreateTime(new Date());
|
|
|
|
|
+ integralRedPacketLogMapper.insertFsIntegralRedPacketLog(redPacketLog);
|
|
|
|
|
+ return redPacketLog;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取用户openId
|
|
|
|
|
+ */
|
|
|
|
|
+ private String getOpenId(FsIntegralWithdrawalParam param, FsUser user) {
|
|
|
|
|
+ if (param.getSource()==2){
|
|
|
|
|
+ FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
|
|
|
|
|
+ if (Objects.nonNull(fsUserWx) && StringUtils.isNotBlank(fsUserWx.getOpenId())) {
|
|
|
|
|
+ return fsUserWx.getOpenId();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (StringUtils.isNotBlank(user.getCourseMaOpenId())) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ handleFsUserWx(user,param.getAppId());
|
|
|
|
|
+ } catch (Exception e){
|
|
|
|
|
+ log.error("【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return user.getCourseMaOpenId();
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (param.getSource()==3){
|
|
|
|
|
+ return user.getAppOpenId();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return user.getMpOpenId();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理用户与小程序的绑定
|
|
|
|
|
+ */
|
|
|
|
|
+ private void handleFsUserWx(FsUser user,String appId) {
|
|
|
|
|
+ FsUserWx fsUserWx = new FsUserWx();
|
|
|
|
|
+ fsUserWx.setType(1);
|
|
|
|
|
+ fsUserWx.setFsUserId(user.getUserId());
|
|
|
|
|
+ fsUserWx.setAppId(appId);
|
|
|
|
|
+ fsUserWx.setOpenId(user.getCourseMaOpenId());
|
|
|
|
|
+ fsUserWx.setUnionId(user.getUnionId());
|
|
|
|
|
+ fsUserWx.setCreateTime(new Date());
|
|
|
|
|
+ fsUserWx.setUpdateTime(new Date());
|
|
|
|
|
+ fsUserWxService.saveOrUpdateByUniqueKey(fsUserWx);
|
|
|
|
|
+
|
|
|
|
|
+ logger.info("zyp \n 【更新或插入用户与小程序{}的绑定关系】:{}", appId, user.getUserId());
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 批量禁用用户
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int disabledUsers(FsUserDisabledUsersParam param) {
|
|
|
|
|
+ if (param.getUserIds() == null || param.getUserIds().isEmpty()) {
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return fsUserMapper.disabledUsers(param);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|