|
|
@@ -38,6 +38,7 @@ import com.fs.live.param.SignPO;
|
|
|
import com.fs.live.service.*;
|
|
|
import com.fs.live.vo.*;
|
|
|
import com.fs.system.service.ISysConfigService;
|
|
|
+import com.github.binarywang.wxpay.exception.WxPayException;
|
|
|
import com.github.pagehelper.PageInfo;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
@@ -373,7 +374,6 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
return R.error("签到任务尚未开启或奖励配置不存在");
|
|
|
}
|
|
|
|
|
|
- // 写入签到记录
|
|
|
LiveSignRecord record = new LiveSignRecord();
|
|
|
record.setLiveId(liveId);
|
|
|
record.setUserId(userId);
|
|
|
@@ -381,84 +381,122 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
record.setCreateTime(new Date());
|
|
|
liveSignRecordService.save(record);
|
|
|
|
|
|
- List<Map<String, Object>> claimResults = new ArrayList<>();
|
|
|
+ List<Map<String, Object>> claimResults = new ArrayList<>(rewards.size());
|
|
|
for (JSONObject item : rewards) {
|
|
|
- Long rewardType = item.getLong("rewardType");
|
|
|
- Long opLogId = item.getLong("opLogId");
|
|
|
- Map<String, Object> one = new HashMap<>();
|
|
|
- one.put("rewardType", rewardType);
|
|
|
- one.put("opLogId", opLogId);
|
|
|
- try {
|
|
|
- if (rewardType != null && rewardType == 2L) {
|
|
|
- // 积分红包:走直播积分红包领取
|
|
|
- RedPO red = new RedPO();
|
|
|
- red.setLiveId(liveId);
|
|
|
- red.setUserId(userId);
|
|
|
- red.setRedId(item.getLong("rewardId"));
|
|
|
- red.setOpLogId(opLogId);
|
|
|
- R r = iLiveRedConfService.claimRedPacket(red);
|
|
|
- one.put("success", Integer.valueOf(200).equals(r.get("code")));
|
|
|
- one.put("msg", r.get("msg"));
|
|
|
- } else if (rewardType != null && rewardType == 5L) {
|
|
|
- // 优惠券:按配置张数发放
|
|
|
- CouponPO coupon = new CouponPO();
|
|
|
- coupon.setLiveId(liveId);
|
|
|
- coupon.setUserId(userId);
|
|
|
- Long couponIssueId = item.getLong("couponIssueId");
|
|
|
- if (couponIssueId == null) {
|
|
|
- Long couponId = item.getLong("rewardId");
|
|
|
- LiveCouponIssue issue = liveCouponIssueService.selectIssueByLiveIdAndCouponId(liveId, couponId);
|
|
|
- couponIssueId = issue != null ? issue.getId() : null;
|
|
|
- }
|
|
|
- coupon.setCouponIssueId(couponIssueId);
|
|
|
- coupon.setGoodsId(item.getLong("goodsId"));
|
|
|
- coupon.setOpLogId(opLogId);
|
|
|
- Integer couponCount = item.getInteger("couponCount");
|
|
|
- coupon.setCouponCount(couponCount != null && couponCount > 0 ? couponCount : 1);
|
|
|
- R r = iLiveCouponService.claimCoupon(coupon);
|
|
|
- one.put("success", Integer.valueOf(200).equals(r.get("code")));
|
|
|
- one.put("msg", r.get("msg"));
|
|
|
- one.put("couponCount", coupon.getCouponCount());
|
|
|
- if (r.get("opLogId") != null) {
|
|
|
- one.put("opLogId", r.get("opLogId"));
|
|
|
- }
|
|
|
- } else if (rewardType != null && rewardType == 6L) {
|
|
|
- // 金额红包:微信商家转账,App 用返回参数确认收款
|
|
|
- R r = claimSignCashRed(liveId, userId, item, sign);
|
|
|
- one.put("success", Integer.valueOf(200).equals(r.get("code")));
|
|
|
- one.put("msg", r.get("msg"));
|
|
|
- // App 调起微信确认收款所需字段
|
|
|
- if (Integer.valueOf(200).equals(r.get("code"))) {
|
|
|
- one.put("needWxConfirm", true);
|
|
|
- one.put("package", r.get("package"));
|
|
|
- one.put("mchId", r.get("mchId"));
|
|
|
- one.put("appId", r.get("appId"));
|
|
|
- one.put("orderCode", r.get("orderCode"));
|
|
|
- one.put("amount", item.getBigDecimal("amount"));
|
|
|
- if (opLogId != null) {
|
|
|
- liveConsoleOpLogService.bindOpLogUser(opLogId, liveId, userId);
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- one.put("success", false);
|
|
|
- one.put("msg", "不支持的奖励类型");
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("签到领取奖励失败, liveId={}, userId={}, rewardType={}", liveId, userId, rewardType, e);
|
|
|
+ claimResults.add(claimOneSignReward(liveId, userId, item, sign));
|
|
|
+ }
|
|
|
+ return buildSignClaimResponse(claimResults);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 领取单项签到奖励:2积分红包 / 5优惠券 / 6金额红包
|
|
|
+ */
|
|
|
+ private Map<String, Object> claimOneSignReward(Long liveId, Long userId, JSONObject item, SignPO sign) {
|
|
|
+ Long rewardType = item.getLong("rewardType");
|
|
|
+ Long opLogId = item.getLong("opLogId");
|
|
|
+ Map<String, Object> one = new HashMap<>();
|
|
|
+ one.put("rewardType", rewardType);
|
|
|
+ one.put("opLogId", opLogId);
|
|
|
+ try {
|
|
|
+ if (Objects.equals(rewardType, 2L)) {
|
|
|
+ claimSignPoints(one, liveId, userId, item, opLogId);
|
|
|
+ } else if (Objects.equals(rewardType, 5L)) {
|
|
|
+ claimSignCoupon(one, liveId, userId, item, opLogId);
|
|
|
+ } else if (Objects.equals(rewardType, 6L)) {
|
|
|
+ claimSignCash(one, liveId, userId, item, sign, opLogId);
|
|
|
+ } else {
|
|
|
one.put("success", false);
|
|
|
- one.put("msg", "领取失败");
|
|
|
+ one.put("msg", "不支持的奖励类型");
|
|
|
}
|
|
|
- claimResults.add(one);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("签到领取奖励失败, liveId={}, userId={}, rewardType={}", liveId, userId, rewardType, e);
|
|
|
+ one.put("success", false);
|
|
|
+ one.put("msg", "领取失败");
|
|
|
}
|
|
|
+ return one;
|
|
|
+ }
|
|
|
|
|
|
- boolean anySuccess = claimResults.stream().anyMatch(m -> Boolean.TRUE.equals(m.get("success")));
|
|
|
- // 有金额红包则返回其 one;否则只返回 msg
|
|
|
+ /** 积分红包 */
|
|
|
+ private void claimSignPoints(Map<String, Object> one, Long liveId, Long userId, JSONObject item, Long opLogId) {
|
|
|
+ RedPO red = new RedPO();
|
|
|
+ red.setLiveId(liveId);
|
|
|
+ red.setUserId(userId);
|
|
|
+ red.setRedId(item.getLong("rewardId"));
|
|
|
+ red.setOpLogId(opLogId);
|
|
|
+ fillClaimResult(one, iLiveRedConfService.claimRedPacket(red));
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 优惠券(按配置张数) */
|
|
|
+ private void claimSignCoupon(Map<String, Object> one, Long liveId, Long userId, JSONObject item, Long opLogId) {
|
|
|
+ CouponPO coupon = new CouponPO();
|
|
|
+ coupon.setLiveId(liveId);
|
|
|
+ coupon.setUserId(userId);
|
|
|
+ Long couponIssueId = item.getLong("couponIssueId");
|
|
|
+ if (couponIssueId == null) {
|
|
|
+ LiveCouponIssue issue = liveCouponIssueService.selectIssueByLiveIdAndCouponId(liveId, item.getLong("rewardId"));
|
|
|
+ couponIssueId = issue != null ? issue.getId() : null;
|
|
|
+ }
|
|
|
+ coupon.setCouponIssueId(couponIssueId);
|
|
|
+ coupon.setGoodsId(item.getLong("goodsId"));
|
|
|
+ coupon.setOpLogId(opLogId);
|
|
|
+ Integer couponCount = item.getInteger("couponCount");
|
|
|
+ coupon.setCouponCount(couponCount != null && couponCount > 0 ? couponCount : 1);
|
|
|
+ R r = iLiveCouponService.claimCoupon(coupon);
|
|
|
+ fillClaimResult(one, r);
|
|
|
+ one.put("couponCount", coupon.getCouponCount());
|
|
|
+ if (r.get("opLogId") != null) {
|
|
|
+ one.put("opLogId", r.get("opLogId"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 金额红包(微信转账,成功时写入确认收款参数) */
|
|
|
+ private void claimSignCash(Map<String, Object> one, Long liveId, Long userId,
|
|
|
+ JSONObject item, SignPO sign, Long opLogId) {
|
|
|
+ R r = claimSignCashRed(liveId, userId, item, sign);
|
|
|
+ fillClaimResult(one, r);
|
|
|
+ if (!isROk(r)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ one.put("needWxConfirm", true);
|
|
|
+ one.put("package", r.get("package"));
|
|
|
+ one.put("mchId", r.get("mchId"));
|
|
|
+ one.put("appId", r.get("appId"));
|
|
|
+ one.put("orderCode", r.get("orderCode"));
|
|
|
+ one.put("amount", item.getBigDecimal("amount"));
|
|
|
+ if (opLogId != null) {
|
|
|
+ liveConsoleOpLogService.bindOpLogUser(opLogId, liveId, userId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void fillClaimResult(Map<String, Object> one, R r) {
|
|
|
+ one.put("success", isROk(r));
|
|
|
+ one.put("msg", r.get("msg"));
|
|
|
+ one.put("code", r.get("code"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isROk(R r) {
|
|
|
+ return Integer.valueOf(200).equals(r.get("code"));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 有金额红包:成功返回 one,失败返回短提示(其他奖励已领:签到已到账,红包:xxx);
|
|
|
+ * 无金额红包:只返回 msg。
|
|
|
+ */
|
|
|
+ private R buildSignClaimResponse(List<Map<String, Object>> claimResults) {
|
|
|
Map<String, Object> cashRed = claimResults.stream()
|
|
|
- .filter(m -> Long.valueOf(6L).equals(m.get("rewardType")))
|
|
|
+ .filter(m -> Objects.equals(6L, m.get("rewardType")))
|
|
|
.findFirst().orElse(null);
|
|
|
if (cashRed != null) {
|
|
|
- return R.ok(cashRed);
|
|
|
+ if (Boolean.TRUE.equals(cashRed.get("success"))) {
|
|
|
+ return R.ok(cashRed);
|
|
|
+ }
|
|
|
+ String cashTip = cashRed.get("msg") != null ? String.valueOf(cashRed.get("msg")) : "领取失败";
|
|
|
+ boolean otherSuccess = claimResults.stream()
|
|
|
+ .filter(m -> !Objects.equals(6L, m.get("rewardType")))
|
|
|
+ .anyMatch(m -> Boolean.TRUE.equals(m.get("success")));
|
|
|
+ return R.error(otherSuccess ? "签到已到账,红包:" + cashTip : cashTip);
|
|
|
}
|
|
|
+ boolean anySuccess = claimResults.stream().anyMatch(m -> Boolean.TRUE.equals(m.get("success")));
|
|
|
return R.ok(anySuccess ? "签到成功" : "签到成功,但奖励领取失败");
|
|
|
}
|
|
|
|
|
|
@@ -472,15 +510,10 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
return R.error("金额红包配置无效");
|
|
|
}
|
|
|
- Live live = liveService.selectLiveByLiveId(liveId);
|
|
|
- if (live == null) {
|
|
|
- return R.error("直播间不存在");
|
|
|
- }
|
|
|
FsUser user = fsUserService.selectFsUserById(userId);
|
|
|
if (user == null) {
|
|
|
return R.error("用户不存在");
|
|
|
}
|
|
|
- // 通过用户绑定销售ID查询销售所属公司,作为红包扣款公司
|
|
|
Long bindCompanyUserId = user.getBindCompanyUserId();
|
|
|
if (bindCompanyUserId == null) {
|
|
|
return R.error("用户未绑定销售,无法发放金额红包");
|
|
|
@@ -490,7 +523,7 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
return R.error("绑定销售不存在或未归属公司,无法发放金额红包");
|
|
|
}
|
|
|
Long companyId = companyUser.getCompanyId();
|
|
|
- // 复用课程发奖 openId 解析逻辑:按 source 取 H5/小程序/App openId
|
|
|
+
|
|
|
FsCourseSendRewardUParam param = new FsCourseSendRewardUParam();
|
|
|
param.setUserId(userId);
|
|
|
param.setCompanyId(companyId);
|
|
|
@@ -502,10 +535,10 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
} catch (CustomException e) {
|
|
|
return R.error(e.getMessage());
|
|
|
}
|
|
|
-
|
|
|
if (StringUtils.isEmpty(openId)) {
|
|
|
return R.error("请使用微信登录后再领取金额红包");
|
|
|
}
|
|
|
+
|
|
|
WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
|
|
|
packetParam.setOpenId(openId);
|
|
|
packetParam.setAmount(amount.setScale(1, RoundingMode.HALF_UP));
|
|
|
@@ -516,10 +549,9 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
packetParam.setUser(user);
|
|
|
try {
|
|
|
R sendResult = paymentService.sendAppRedPacket(packetParam);
|
|
|
- if (!Integer.valueOf(200).equals(sendResult.get("code"))) {
|
|
|
+ if (!isROk(sendResult)) {
|
|
|
return sendResult;
|
|
|
}
|
|
|
- // 写入直播奖励流水(现金,来源类型 7=签到)
|
|
|
try {
|
|
|
LiveRewardRecord rewardRecord = new LiveRewardRecord();
|
|
|
rewardRecord.setLiveId(liveId);
|
|
|
@@ -537,10 +569,48 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
return sendResult;
|
|
|
} catch (Exception e) {
|
|
|
log.error("签到金额红包发放失败, liveId={}, userId={}, amount={}", liveId, userId, amount, e);
|
|
|
- return R.error("金额红包发放失败:" + e.getMessage());
|
|
|
+ return R.error(resolveCashRedTipByException(e));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 根据微信转账异常 errCode 转成短提示(如 NOT_ENOUGH → 资金不足,请联系销售!)
|
|
|
+ */
|
|
|
+ private String resolveCashRedTipByException(Throwable e) {
|
|
|
+ WxPayException wxEx = findWxPayException(e);
|
|
|
+ String errCode = null;
|
|
|
+ if (wxEx != null) {
|
|
|
+ errCode = wxEx.getErrCode();
|
|
|
+ // V3 有时 errCode 为空,从 customErrorMsg 兜底
|
|
|
+ if (StringUtils.isEmpty(errCode) && StringUtils.isNotEmpty(wxEx.getCustomErrorMsg())
|
|
|
+ && wxEx.getCustomErrorMsg().contains("资金不足")) {
|
|
|
+ errCode = "NOT_ENOUGH";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(errCode) && e.getMessage() != null && e.getMessage().contains("errCode=NOT_ENOUGH")) {
|
|
|
+ errCode = "NOT_ENOUGH";
|
|
|
+ }
|
|
|
+ return cashRedTipByWxErrCode(errCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String cashRedTipByWxErrCode(String errCode) {
|
|
|
+ if ("NOT_ENOUGH".equalsIgnoreCase(errCode)) {
|
|
|
+ return "资金不足,请联系销售!";
|
|
|
+ }
|
|
|
+ return "领取失败";
|
|
|
+ }
|
|
|
+
|
|
|
+ private WxPayException findWxPayException(Throwable e) {
|
|
|
+ Throwable cur = e;
|
|
|
+ while (cur != null) {
|
|
|
+ if (cur instanceof WxPayException) {
|
|
|
+ return (WxPayException) cur;
|
|
|
+ }
|
|
|
+ cur = cur.getCause();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 按来源获取用户 openId:1=H5 2=小程序 3=App
|
|
|
*/
|