|
|
@@ -13,6 +13,8 @@ import com.fs.common.core.redis.RedisCache;
|
|
|
import com.fs.common.utils.DateUtils;
|
|
|
import com.fs.common.utils.DictUtils;
|
|
|
import com.fs.common.utils.StringUtils;
|
|
|
+import com.fs.his.domain.FsUser;
|
|
|
+import com.fs.his.service.IFsUserService;
|
|
|
import com.fs.live.domain.*;
|
|
|
import com.fs.live.mapper.LiveCouponIssueMapper;
|
|
|
import com.fs.live.mapper.LiveCouponIssueUserMapper;
|
|
|
@@ -60,6 +62,8 @@ public class LiveCouponServiceImpl implements ILiveCouponService
|
|
|
private LiveCouponIssueMapper liveCouponIssueMapper;
|
|
|
@Autowired
|
|
|
private ILiveConsoleOpLogService liveConsoleOpLogService;
|
|
|
+ @Autowired
|
|
|
+ private IFsUserService fsUserService;
|
|
|
|
|
|
/**
|
|
|
* 查询优惠券
|
|
|
@@ -470,9 +474,14 @@ public class LiveCouponServiceImpl implements ILiveCouponService
|
|
|
return R.ok().put("data", detail);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 销售扫码核销优惠券。
|
|
|
+ * <p>流程:参数校验 → 查券 → 绑定销售校验 → 状态/过期校验 → 落库核销 → 返回详情</p>
|
|
|
+ */
|
|
|
@Override
|
|
|
@Transactional
|
|
|
public R verifyCoupon(LiveCouponVerifyParam param) {
|
|
|
+ // 1. 基础参数校验
|
|
|
if (param.getVerifyUserId() == null) {
|
|
|
return R.error("销售未登录");
|
|
|
}
|
|
|
@@ -480,57 +489,122 @@ public class LiveCouponServiceImpl implements ILiveCouponService
|
|
|
return R.error("核销码不能为空");
|
|
|
}
|
|
|
|
|
|
- LiveCouponUser couponUser;
|
|
|
- if (StringUtils.isNotEmpty(param.getVerifyCode())) {
|
|
|
- couponUser = liveCouponUserService.selectLiveCouponUserByVerifyCode(param.getVerifyCode());
|
|
|
- } else {
|
|
|
- couponUser = liveCouponUserService.selectLiveCouponUserById(param.getCouponUserId());
|
|
|
- }
|
|
|
+ // 2. 按核销码或发放记录ID定位优惠券
|
|
|
+ LiveCouponUser couponUser = resolveCouponUser(param);
|
|
|
if (couponUser == null || Objects.equals(couponUser.getIsDel(), 1)) {
|
|
|
return R.error("优惠券不存在");
|
|
|
}
|
|
|
|
|
|
- Date now = DateUtils.getNowDate();
|
|
|
- if (couponUser.getStatus() != null && couponUser.getStatus() == 1) {
|
|
|
+ // 3. 校验持券用户是否绑定当前销售(防跨销售核销)
|
|
|
+ R checkResult = checkBindSales(couponUser, param.getVerifyUserId());
|
|
|
+ if (checkResult != null) {
|
|
|
+ return checkResult;
|
|
|
+ }
|
|
|
+ // 4. 校验优惠券状态是否可核销(含过期同步)
|
|
|
+ checkResult = checkCouponVerifiable(couponUser);
|
|
|
+ if (checkResult != null) {
|
|
|
+ return checkResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 落库标记已核销,并返回最新详情
|
|
|
+ markCouponVerified(couponUser, param.getVerifyUserId());
|
|
|
+ LiveCouponUserDetailVo detail = liveCouponUserService.selectLiveCouponUserDetailById(couponUser.getId());
|
|
|
+ fillCouponStatusName(detail);
|
|
|
+ return R.ok("核销成功").put("data", detail);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析待核销优惠券:优先按核销码查询,否则按发放记录ID查询。
|
|
|
+ *
|
|
|
+ * @param param 核销参数(verifyCode / couponUserId)
|
|
|
+ * @return 优惠券发放记录,未找到时由调用方处理
|
|
|
+ */
|
|
|
+ private LiveCouponUser resolveCouponUser(LiveCouponVerifyParam param) {
|
|
|
+ if (StringUtils.isNotEmpty(param.getVerifyCode())) {
|
|
|
+ return liveCouponUserService.selectLiveCouponUserByVerifyCode(param.getVerifyCode());
|
|
|
+ }
|
|
|
+ return liveCouponUserService.selectLiveCouponUserById(param.getCouponUserId());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验持券用户是否绑定当前登录销售。
|
|
|
+ * <p>通过优惠券上的 userId 查 fs_user.bind_company_user_id,与 verifyUserId 比对,防止跨销售核销。</p>
|
|
|
+ *
|
|
|
+ * @param couponUser 优惠券发放记录
|
|
|
+ * @param verifyUserId 当前登录销售ID
|
|
|
+ * @return 校验失败返回错误结果;通过返回 null
|
|
|
+ */
|
|
|
+ private R checkBindSales(LiveCouponUser couponUser, Long verifyUserId) {
|
|
|
+ if (couponUser.getUserId() == null) {
|
|
|
+ return R.error("优惠券所属用户不存在");
|
|
|
+ }
|
|
|
+ FsUser fsUser = fsUserService.selectFsUserByUserId(Long.valueOf(couponUser.getUserId()));
|
|
|
+ if (fsUser == null) {
|
|
|
+ return R.error("优惠券所属用户不存在");
|
|
|
+ }
|
|
|
+ // bind_company_user_id 为空或与当前销售不一致,均不允许核销
|
|
|
+ if (!Objects.equals(fsUser.getBindCompanyUserId(), verifyUserId)) {
|
|
|
+ return R.error("该用户未绑定当前销售,无法核销");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验优惠券是否处于可核销状态。
|
|
|
+ * <p>已核销、已过期不可核销;若未核销但已超过 limitTime,则同步落库为已过期后再拒绝。</p>
|
|
|
+ *
|
|
|
+ * @param couponUser 优惠券发放记录
|
|
|
+ * @return 校验失败返回错误结果;通过返回 null
|
|
|
+ */
|
|
|
+ private R checkCouponVerifiable(LiveCouponUser couponUser) {
|
|
|
+ Integer status = couponUser.getStatus();
|
|
|
+ // 0-未核销 1-已核销 2-已过期
|
|
|
+ if (status != null && status == 1) {
|
|
|
return R.error("优惠券已核销");
|
|
|
}
|
|
|
- if (couponUser.getStatus() != null && couponUser.getStatus() == 2) {
|
|
|
+ if (status != null && status == 2) {
|
|
|
return R.error("优惠券已过期");
|
|
|
}
|
|
|
- if (couponUser.getLimitTime() != null && couponUser.getLimitTime().before(now)) {
|
|
|
- LiveCouponUser expired = new LiveCouponUser();
|
|
|
- expired.setId(couponUser.getId());
|
|
|
- expired.setStatus(2);
|
|
|
- expired.setIsFail(0);
|
|
|
- expired.setUpdateTime(now);
|
|
|
- liveCouponUserService.updateLiveCouponUser(expired);
|
|
|
+ // 状态仍为未核销,但实际已过有效期时,先同步为已过期
|
|
|
+ expireCouponIfNeeded(couponUser, DateUtils.getNowDate());
|
|
|
+ if (Objects.equals(couponUser.getStatus(), 2)) {
|
|
|
return R.error("优惠券已过期");
|
|
|
}
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * 将优惠券标记为已核销并写入核销人、核销时间;若缺少核销码则补生成。
|
|
|
+ *
|
|
|
+ * @param couponUser 优惠券发放记录
|
|
|
+ * @param verifyUserId 核销销售ID
|
|
|
+ */
|
|
|
+ private void markCouponVerified(LiveCouponUser couponUser, Long verifyUserId) {
|
|
|
+ Date now = DateUtils.getNowDate();
|
|
|
LiveCouponUser update = new LiveCouponUser();
|
|
|
update.setId(couponUser.getId());
|
|
|
update.setStatus(1);
|
|
|
update.setUseTime(now);
|
|
|
update.setVerifyTime(now);
|
|
|
- update.setVerifyUserId(param.getVerifyUserId());
|
|
|
+ update.setVerifyUserId(verifyUserId);
|
|
|
update.setUpdateTime(now);
|
|
|
if (StringUtils.isEmpty(couponUser.getVerifyCode())) {
|
|
|
update.setVerifyCode(generateVerifyCode());
|
|
|
}
|
|
|
liveCouponUserService.updateLiveCouponUser(update);
|
|
|
-
|
|
|
- LiveCouponUserDetailVo detail = liveCouponUserService.selectLiveCouponUserDetailById(couponUser.getId());
|
|
|
- fillCouponStatusName(detail);
|
|
|
- return R.ok("核销成功").put("data", detail);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 未核销且已过期的优惠券同步为已过期(与 verifyCoupon 逻辑一致)
|
|
|
+ * 若优惠券未核销且已超过有效期,则同步更新为已过期状态。
|
|
|
+ *
|
|
|
+ * @param couponUser 优惠券发放记录(成功过期后会回写 status=2)
|
|
|
+ * @param now 当前时间
|
|
|
*/
|
|
|
private void expireCouponIfNeeded(LiveCouponUser couponUser, Date now) {
|
|
|
if (couponUser == null) {
|
|
|
return;
|
|
|
}
|
|
|
+ // 仅处理未核销状态
|
|
|
if (couponUser.getStatus() != null && couponUser.getStatus() != 0) {
|
|
|
return;
|
|
|
}
|
|
|
@@ -546,6 +620,9 @@ public class LiveCouponServiceImpl implements ILiveCouponService
|
|
|
couponUser.setStatus(2);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 填充优惠券状态中文名称(未核销 / 已核销 / 已过期)。
|
|
|
+ */
|
|
|
private void fillCouponStatusName(LiveCouponUserDetailVo detail) {
|
|
|
if (detail == null || detail.getStatus() == null) {
|
|
|
return;
|
|
|
@@ -563,6 +640,9 @@ public class LiveCouponServiceImpl implements ILiveCouponService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 详情中若无核销码,则补生成并落库,便于前端展示二维码。
|
|
|
+ */
|
|
|
private void ensureVerifyCode(LiveCouponUserDetailVo detail) {
|
|
|
if (detail == null || StringUtils.isNotEmpty(detail.getVerifyCode())) {
|
|
|
return;
|
|
|
@@ -575,6 +655,9 @@ public class LiveCouponServiceImpl implements ILiveCouponService
|
|
|
detail.setVerifyCode(update.getVerifyCode());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 生成优惠券核销码(前缀 LC + 时间戳 + 随机数)。
|
|
|
+ */
|
|
|
private String generateVerifyCode() {
|
|
|
return "LC" + System.currentTimeMillis() + (int) (Math.random() * 1000);
|
|
|
}
|