积分模块相关代码

This commit is contained in:
谭凯凯
2024-11-01 16:31:44 +08:00
committed by Tankaikai
parent a9bfd9b93b
commit 41edba65fc
10 changed files with 516 additions and 75 deletions

View File

@@ -20,7 +20,15 @@ public interface TbPointsExchangeRecordService extends IService<TbPointsExchange
void checkout(String couponCode);
TbPointsExchangeRecord exchange(TbPointsExchangeRecord record);
TbPointsExchangeRecord create(TbPointsExchangeRecord record);
TbPointsExchangeRecord pay(TbPointsExchangeRecord record);
void callback(TbPointsExchangeRecord record);
void cancel(TbPointsExchangeRecord record);
void refund(TbPointsExchangeRecord record);
Map<String, Object> total(Map<String, Object> params);
}

View File

@@ -5,19 +5,26 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.map.MapProxy;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chaozhanggui.system.cashierservice.dao.TbMerchantThirdApplyMapper;
import com.chaozhanggui.system.cashierservice.entity.*;
import com.chaozhanggui.system.cashierservice.exception.MsgException;
import com.chaozhanggui.system.cashierservice.mapper.*;
import com.chaozhanggui.system.cashierservice.service.TbPointsExchangeRecordService;
import com.chaozhanggui.system.cashierservice.thirdpay.resp.OrderReturnResp;
import com.chaozhanggui.system.cashierservice.thirdpay.resp.PublicResp;
import com.chaozhanggui.system.cashierservice.thirdpay.resp.WxScanPayResp;
import com.chaozhanggui.system.cashierservice.thirdpay.service.ThirdPayService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -37,6 +44,17 @@ import java.util.Map;
@Primary
public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExchangeRecordMapper, TbPointsExchangeRecord> implements TbPointsExchangeRecordService {
private static final Map<String, String> payMethod = MapUtil.builder("POINTS", "积分支付")
.put("WECHAT", "积分+微信")
.put("ALIPAY", "积分+支付宝")
.build();
@Value("${thirdPay.url}")
private String thirdUrl;
@Value("${thirdPay.pointsGoodsOrderCallBack}")
private String pointsGoodsOrderCallBack;
@Autowired
private TbPointsBasicSettingMapper tbPointsBasicSettingMapper;
@@ -49,6 +67,15 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
@Autowired
private TbMemberPointsLogMapper tbMemberPointsLogMapper;
@Autowired
private MpShopInfoMapper mpShopInfoMapper;
@Autowired
private TbMerchantThirdApplyMapper tbMerchantThirdApplyMapper;
@Autowired
private ThirdPayService thirdPayService;
private LambdaQueryWrapper<TbPointsExchangeRecord> getWrapper(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
String keywords = mapProxy.getStr("keywords");
@@ -91,6 +118,7 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
}
@Override
@Transactional(rollbackFor = Exception.class)
public void checkout(String couponCode) {
if (StrUtil.isBlank(couponCode)) {
throw new MsgException("兑换券券码不能为空");
@@ -102,11 +130,18 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
entity.setStatus("done");
entity.setUpdateTime(new Date());
super.updateById(entity);
TbPointsGoodsSetting goods = tbPointsGoodsSettingMapper.selectById(entity.getPointsGoodsId());
if (goods == null) {
throw new MsgException("积分商品不存在");
}
// 更新累计兑换数量
goods.setTotalExchangeCount(goods.getTotalExchangeCount() + 1);
goods.setUpdateTime(new Date());
tbPointsGoodsSettingMapper.updateById(goods);
}
@Override
@Transactional(rollbackFor = Exception.class)
public TbPointsExchangeRecord exchange(TbPointsExchangeRecord record) {
private void verify(TbPointsExchangeRecord record, TbPointsBasicSetting basic, TbPointsGoodsSetting goods, TbMemberPoints memberPoints) {
try {
Assert.notNull(record.getShopId(), "{}({})不能为空", "店铺id", "shopId");
Assert.notNull(record.getPointsGoodsId(), "{}({})不能为空", "积分商品id", "pointsGoodsId");
@@ -117,14 +152,14 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
} catch (IllegalArgumentException e) {
throw new MsgException(e.getMessage());
}
TbPointsBasicSetting basic = tbPointsBasicSettingMapper.selectOne(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, record.getShopId()));
basic = tbPointsBasicSettingMapper.selectOne(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, record.getShopId()));
if (basic == null) {
throw new MsgException("未配置积分锁客基本设置");
throw new MsgException("商家未配置积分锁客基本设置");
}
if (basic.getEnablePointsMall() != 1) {
throw new MsgException("积分商城未开启");
}
TbPointsGoodsSetting goods = tbPointsGoodsSettingMapper.selectById(record.getPointsGoodsId());
goods = tbPointsGoodsSettingMapper.selectById(record.getPointsGoodsId());
if (goods == null) {
throw new MsgException("兑换的商品信息不存在");
}
@@ -142,26 +177,183 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
if (quantity <= 0) {
throw new MsgException("兑换的商品库存不足");
}
TbMemberPoints memberPoints = tbMemberPointsMapper.selectOne(Wrappers.<TbMemberPoints>lambdaQuery().eq(TbMemberPoints::getMemberId, record.getMemberId()));
memberPoints = tbMemberPointsMapper.selectOne(Wrappers.<TbMemberPoints>lambdaQuery().eq(TbMemberPoints::getMemberId, record.getMemberId()));
if (memberPoints == null) {
throw new MsgException("会员积分不足无法兑换这个商品");
throw new MsgException("会员积分不足无法兑换商品");
}
Integer accountPoints = memberPoints.getAccountPoints();
Integer requiredPoints = goods.getRequiredPoints();
if (accountPoints < requiredPoints) {
throw new MsgException("会员积分不足无法兑换这个商品");
throw new MsgException("会员积分不足无法兑换商品");
}
BigDecimal extraPrice = goods.getExtraPrice();
record.setExtraPaymentAmount(extraPrice);
record.setSpendPoints(requiredPoints);
}
@Override
public TbPointsExchangeRecord create(TbPointsExchangeRecord record) {
TbPointsBasicSetting basic = null;
TbPointsGoodsSetting goods = null;
TbMemberPoints memberPoints = null;
verify(record, basic, goods, memberPoints);
record.setExtraPaymentAmount(goods.getExtraPrice());
record.setSpendPoints(goods.getRequiredPoints());
Snowflake seqNo = IdUtil.getSnowflake(0, 0);
String orderNo = DateUtil.format(new Date(), "yyyyMMddHH") + StrUtil.subSuf(seqNo.nextIdStr(), -12);
record.setOrderNo(orderNo);
record.setCouponCode(IdUtil.getSnowflakeNextIdStr());
record.setStatus("waiting");
record.setStatus("unpaid");
record.setCreateTime(new Date());
// 生成订单
super.save(record);
return record;
}
@Override
@Transactional(rollbackFor = Exception.class)
public TbPointsExchangeRecord pay(TbPointsExchangeRecord record) {
if (record.getId() == null) {
throw new MsgException("订单ID不能为空");
}
TbPointsExchangeRecord entity = super.getById(record.getId());
if (entity == null) {
throw new MsgException("订单不存在");
}
TbPointsBasicSetting basic = null;
TbPointsGoodsSetting goods = null;
TbMemberPoints memberPoints = null;
try {
verify(entity, basic, goods, memberPoints);
} catch (Exception e) {
throw new MsgException(e.getMessage().concat(",请您取消订单"));
}
if (!"unpaid".equals(record.getStatus())) {
throw new MsgException("订单状态异常,请刷新后重试");
}
if (StrUtil.isBlank(record.getPayType())) {
throw new MsgException("支付方式不能为空");
}
entity.setPayType(record.getPayType().toUpperCase());
if (!payMethod.keySet().contains(record.getPayType().toUpperCase())) {
throw new MsgException("支付方式不合法");
}
// 设置支付方式
entity.setPayMethod(payMethod.get(record.getPayType().toUpperCase()));
// 纯积分支付并且商品需要额外支付金额,需要抛出异常
if ("POINTS".equals(entity.getPayType()) && NumberUtil.isGreater(record.getExtraPaymentAmount(), BigDecimal.ZERO)) {
throw new MsgException("此商品需要额外支付金额");
}
if (!"POINTS".equals(entity.getPayType()) && NumberUtil.equals(record.getExtraPaymentAmount(), BigDecimal.ZERO)) {
throw new MsgException("此商品不需要额外支付金额");
}
// 如果不需要额外支付
if (NumberUtil.equals(record.getExtraPaymentAmount(), BigDecimal.ZERO)) {
// 设置核销券码
entity.setCouponCode(IdUtil.getSnowflakeNextIdStr());
entity.setStatus("waiting");
entity.setPayTime(new Date());
super.updateById(entity);
waitingAfter(entity);
return entity;
}
if (StrUtil.isBlank(record.getOpenId())) {
throw new MsgException("openId/userId不能为空");
}
if (StrUtil.isBlank(record.getIp())) {
throw new MsgException("无法获取用户ip地址");
}
// 需要额外支付
TbShopInfo shopInfo = mpShopInfoMapper.selectById(entity.getShopId());
if (shopInfo == null) {
throw new MsgException("店铺信息不存在");
}
TbMerchantThirdApply thirdApply = tbMerchantThirdApplyMapper.selectByPrimaryKey(Integer.valueOf(shopInfo.getMerchantId()));
if (thirdApply == null) {
throw new MsgException("支付通道不存在");
}
if ("alipay".equalsIgnoreCase(entity.getPayType()) && StrUtil.isBlank(thirdApply.getAlipaySmallAppid())) {
throw new MsgException("店铺未配置支付宝小程序appId");
}
// 准备支付参数
// 应用ID
String appId = thirdApply.getAppId();
String appToken = thirdApply.getAppToken();
String storeId = thirdApply.getStoreId();
// 订单标题(商品名称)
String subject = entity.getPointsGoodsName();
// 商品描述
String body = StrUtil.format("兑换商品:{} * {}", entity.getPointsGoodsName(), "1");
// 交易金额 单位分 100 表示1元
long amount = NumberUtil.mul(entity.getExtraPaymentAmount(), new BigDecimal("100")).longValue();
// 支付方式
String payType = entity.getPayType().toUpperCase();
// 子商户APPID
String subAppid = thirdApply.getSmallAppid();
if ("alipay".equalsIgnoreCase(entity.getPayType())) {
subAppid = thirdApply.getAlipaySmallAppid();
}
// 用户唯一标识 微信支付时传入用户的openId支付宝支付和银联支付时传入用户的userId
String openId = record.getOpenId();
// 用户IP
String clientIp = record.getIp();
// 商户订单号 mchOrderNo
String mchOrderNo = IdUtil.getSnowflakeNextIdStr();
// 回调地址
String notifyUrl = pointsGoodsOrderCallBack;
// 支付成功后的跳转页面
String returnUrl = null;
PublicResp<WxScanPayResp> publicResp;
try {
publicResp = thirdPayService.scanpay(thirdUrl, appId, subject, body, amount, payType, subAppid, openId, clientIp, mchOrderNo, storeId, notifyUrl, returnUrl, appToken);
} catch (Exception e) {
log.error("拉起支付失败:", e);
throw new MsgException(StrUtil.format("拉起支付失败:{}", e.getMessage()));
}
if (publicResp == null) {
throw new MsgException("拉起支付失败:无响应");
}
if (!"000000".equals(publicResp.getCode())) {
throw new MsgException(publicResp.getMsg());
}
WxScanPayResp payResp = publicResp.getObjData();
if (!"TRADE_AWAIT".equals(payResp.getState())) {
throw new MsgException(StrUtil.format("拉起支付失败:{}", payResp.getState()));
}
entity.setPayOrderId(payResp.getPayOrderId());
super.updateById(entity);
return entity;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void callback(TbPointsExchangeRecord record) {
TbPointsExchangeRecord entity = baseMapper.selectOne(Wrappers.<TbPointsExchangeRecord>lambdaQuery().eq(TbPointsExchangeRecord::getPayOrderId, record.getPayOrderId()));
if (entity == null) {
throw new MsgException("对应的支付订单不存在");
}
entity.setStatus("waiting");
entity.setPayTime(record.getPayTime());
entity.setChannelTradeNo(record.getChannelTradeNo());
entity.setCouponCode(IdUtil.getSnowflakeNextIdStr());
super.updateById(entity);
waitingAfter(entity);
}
/**
* 支付完成的后续操作
*
* @param entity
*/
private void waitingAfter(TbPointsExchangeRecord entity) {
TbPointsGoodsSetting goods = tbPointsGoodsSettingMapper.selectById(entity.getPointsGoodsId());
if (goods == null) {
throw new MsgException("积分商品不存在");
}
TbMemberPoints memberPoints = tbMemberPointsMapper.selectOne(Wrappers.<TbMemberPoints>lambdaQuery().eq(TbMemberPoints::getMemberId, entity.getMemberId()));
if (memberPoints == null) {
throw new MsgException("会员积分不足无法兑换此商品");
}
Integer quantity = goods.getQuantity();
Integer accountPoints = memberPoints.getAccountPoints();
Integer requiredPoints = goods.getRequiredPoints();
// 扣减积分
memberPoints.setAccountPoints(accountPoints - requiredPoints);
memberPoints.setLastPointsChangeTime(new Date());
@@ -173,21 +365,130 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
tbPointsGoodsSettingMapper.updateById(goods);
// 记录积分浮动流水
TbMemberPointsLog log = new TbMemberPointsLog();
log.setShopId(record.getShopId());
log.setMemberId(record.getMemberId());
log.setMemberName(record.getMemberName());
log.setMobile(record.getMobile());
log.setAvatarUrl(record.getAvatarUrl());
log.setContent(StrUtil.format("兑换商品:{} * {}", record.getPointsGoodsName(), "1"));
log.setShopId(entity.getShopId());
log.setMemberId(entity.getMemberId());
log.setMemberName(entity.getMemberName());
log.setMobile(entity.getMobile());
log.setAvatarUrl(entity.getAvatarUrl());
log.setContent(StrUtil.format("兑换商品:{} * {}", entity.getPointsGoodsName(), "1"));
log.setFloatType("subtract");
log.setFloatPoints(-requiredPoints);
log.setCreateTime(new Date());
tbMemberPointsLogMapper.insert(log);
// 更新累计兑换数量
goods.setTotalExchangeCount(goods.getTotalExchangeCount() + 1);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void cancel(TbPointsExchangeRecord record) {
if (record.getId() == null) {
throw new MsgException("订单ID不能为空");
}
TbPointsExchangeRecord entity = super.getById(record.getId());
if (entity == null) {
throw new MsgException("订单不存在");
}
if (!"unpaid".equals(entity.getStatus())) {
throw new MsgException("当前订单状态不支持取消");
}
entity.setStatus("cancel");
entity.setCancelOrRefundReason(record.getCancelOrRefundReason());
entity.setCancelOrRefundTime(new Date());
super.updateById(entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void refund(TbPointsExchangeRecord record) {
if (record.getId() == null) {
throw new MsgException("订单ID不能为空");
}
TbPointsExchangeRecord entity = super.getById(record.getId());
if (entity == null) {
throw new MsgException("订单不存在");
}
if (!"waiting".equals(entity.getStatus())) {
throw new MsgException("当前订单状态不支持退款");
}
// 先退积分
entity.setStatus("cancel");
entity.setCancelOrRefundReason(record.getCancelOrRefundReason());
entity.setCancelOrRefundTime(new Date());
super.updateById(entity);
TbMemberPoints memberPoints = tbMemberPointsMapper.selectOne(Wrappers.<TbMemberPoints>lambdaQuery().eq(TbMemberPoints::getMemberId, entity.getMemberId()));
if (memberPoints == null) {
throw new MsgException("会员信息不存在");
}
memberPoints.setAccountPoints(memberPoints.getAccountPoints() + entity.getSpendPoints());
memberPoints.setLastPointsChangeTime(new Date());
memberPoints.setLastFloatPoints(entity.getSpendPoints());
tbMemberPointsMapper.updateById(memberPoints);
// 回滚库存
TbPointsGoodsSetting goods = tbPointsGoodsSettingMapper.selectById(entity.getPointsGoodsId());
if (goods == null) {
throw new MsgException("积分商品不存在");
}
goods.setQuantity(goods.getQuantity() + 1);
goods.setUpdateTime(new Date());
tbPointsGoodsSettingMapper.updateById(goods);
return record;
// 记录积分浮动流水
TbMemberPointsLog log = new TbMemberPointsLog();
log.setShopId(entity.getShopId());
log.setMemberId(entity.getMemberId());
log.setMemberName(entity.getMemberName());
log.setMobile(entity.getMobile());
log.setAvatarUrl(entity.getAvatarUrl());
log.setContent(StrUtil.format("(退单)兑换商品:{} * {}", entity.getPointsGoodsName(), "1"));
log.setFloatType("add");
log.setFloatPoints(+entity.getSpendPoints());
log.setCreateTime(new Date());
tbMemberPointsLogMapper.insert(log);
// 如果额外付款了则需要退款
if (NumberUtil.equals(entity.getExtraPaymentAmount(), BigDecimal.ZERO)) {
return;
}
if (StrUtil.isBlank(record.getOpenId())) {
throw new MsgException("openId/userId不能为空");
}
if (StrUtil.isBlank(record.getIp())) {
throw new MsgException("无法获取用户ip地址");
}
// 需要额外支付
TbShopInfo shopInfo = mpShopInfoMapper.selectById(entity.getShopId());
if (shopInfo == null) {
throw new MsgException("店铺信息不存在");
}
TbMerchantThirdApply thirdApply = tbMerchantThirdApplyMapper.selectByPrimaryKey(Integer.valueOf(shopInfo.getMerchantId()));
if (thirdApply == null) {
throw new MsgException("支付通道不存在");
}
if ("alipay".equalsIgnoreCase(entity.getPayType()) && StrUtil.isBlank(thirdApply.getAlipaySmallAppid())) {
throw new MsgException("店铺未配置支付宝小程序appId");
}
// 准备退款参数
// 应用ID
String appId = thirdApply.getAppId();
String appToken = thirdApply.getAppToken();
// 交易金额 单位分 100 表示1元
long amount = NumberUtil.mul(record.getExtraPaymentAmount(), new BigDecimal("100")).longValue();
// 退款订单号
String mchRefundNo = entity.getOrderNo();
PublicResp<OrderReturnResp> publicResp;
try {
publicResp = thirdPayService.returnOrder(thirdUrl, appId, mchRefundNo, entity.getPayOrderId(), null, entity.getCancelOrRefundReason(), amount, null, null, appToken);
} catch (Exception e) {
super.log.error("发起退款失败:", e);
throw new MsgException(StrUtil.format("发起退款失败:{}", e.getMessage()));
}
if (publicResp == null) {
throw new MsgException("拉起支付失败:无响应");
}
if (!"000000".equals(publicResp.getCode())) {
throw new MsgException(publicResp.getMsg());
}
OrderReturnResp returnResp = publicResp.getObjData();
if (!"SUCCESS".equals(returnResp.getState())) {
throw new MsgException(StrUtil.format("退款失败原因:{}",returnResp.getState()));
}
}
@Override