积分模块相关接口

This commit is contained in:
谭凯凯 2024-11-05 15:01:53 +08:00 committed by Tankaikai
parent 029213e068
commit adb0e978d0
11 changed files with 293 additions and 132 deletions

View File

@ -46,11 +46,18 @@ public class TbPointsExchangeRecordController {
return ResponseEntity.ok().build();
}
@PostMapping("exchange")
@ApiOperation("兑换")
public ResponseEntity exchange(@RequestBody TbPointsExchangeRecord record) {
TbPointsExchangeRecord data = tbPointsExchangeRecordService.exchange(record);
return ResponseEntity.ok().body(data);
@PostMapping("cancel")
@ApiOperation("取消")
public ResponseEntity cancel(@RequestBody TbPointsExchangeRecord record) {
tbPointsExchangeRecordService.cancel(record);
return ResponseEntity.ok().build();
}
@PostMapping("refund")
@ApiOperation("退单")
public ResponseEntity refund(@RequestBody TbPointsExchangeRecord record) {
tbPointsExchangeRecordService.refund(record);
return ResponseEntity.ok().build();
}
@GetMapping("total")

View File

@ -24,6 +24,10 @@ public class OrderDeductionPointsDTO {
* 根据策略计算出的最多可以抵扣的金额
*/
private BigDecimal maxDeductionAmount;
/**
* 下单实付抵扣门槛(实付金额不低于这个值)
*/
private BigDecimal minPaymentAmount;
/**
* 下单积分抵扣门槛(每次使用不低于这个值)
*/

View File

@ -57,11 +57,16 @@ public class TbMemberPoints {
* 最近一次积分变动时间
*/
@TableField("last_points_change_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date lastPointsChangeTime;
/**
* 最近一次浮动积分
*/
@TableField("last_float_points")
private Integer lastFloatPoints;
/**
* 是否会员 1- 0-
*/
@TableField("is_vip")
private Integer vip;
}

View File

@ -65,6 +65,6 @@ public class TbMemberPointsLog {
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
}

View File

@ -35,6 +35,10 @@ public class TbPointsBasicSetting {
* 开启消费赠送积分 1-开启 0-关闭
*/
private Integer enableRewards;
/**
* 赠积分适用群体 all-全部 vip-仅会员
*/
private String rewardsGroup;
/**
* 每消费xx元赠送1积分
*/
@ -44,9 +48,13 @@ public class TbPointsBasicSetting {
*/
private Integer enableDeduction;
/**
* 下单积分抵扣门槛
* 抵扣适用群体 all-全部 vip-仅会员
*/
private String deductionGroup;
/**
* 下单实付抵扣门槛
*/
private Integer minDeductionPoint;
private BigDecimal minPaymentAmount;
/**
* 下单最高抵扣比例
*/
@ -66,6 +74,6 @@ public class TbPointsBasicSetting {
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
}

View File

@ -2,6 +2,8 @@ package cn.ysk.cashier.mybatis.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -78,18 +80,48 @@ public class TbPointsExchangeRecord {
*/
private String couponCode;
/**
* 状态 waiting-待自取 done-已完成
* 支付平台订单号
*/
private String payOrderId;
/**
* 渠道订单号(微信/支付宝订单号)
*/
private String channelTradeNo;
/**
* 支付方式 积分支付/积分+微信/积分+支付宝
*/
private String payMethod;
/**
* 支付类型 POINTS-积分 WECHAT-微信 ALIPAY-支付宝 UNIONPAY-银联云闪付
*/
private String payType;
/**
* 状态 unpaid-待支付 waiting-待自取 done-已完成 cancel-已取消
*/
private String status;
/**
* 取消/退款原因
*/
private String cancelOrRefundReason;
/**
* 取消/退款时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date cancelOrRefundTime;
/**
* 实际支付时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date payTime;
/**
* 创建时间下单时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 更新时间核销时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
@TableField(value = "count(*)", select = false, insertStrategy = FieldStrategy.NEVER, updateStrategy = FieldStrategy.NEVER)
@ -97,4 +129,24 @@ public class TbPointsExchangeRecord {
@TableField(value = "sum(extra_payment_amount)", select = false, insertStrategy = FieldStrategy.NEVER, updateStrategy = FieldStrategy.NEVER)
private BigDecimal totalAmount;
/**
* 用户ip
*/
@JsonIgnore
@TableField(exist = false)
private String ip;
/**
* 微信openId/支付完userId
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@TableField(exist = false)
private String openId;
/**
* 拉起支付所需信息
*/
@TableField(exist = false)
private String payInfo;
}

View File

@ -75,12 +75,12 @@ public class TbPointsGoodsSetting {
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
/**
* 逻辑删除标志 1- 0-

View File

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

View File

@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapProxy;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.dto.points.OrderDeductionPointsDTO;
import cn.ysk.cashier.exception.BadRequestException;
@ -82,7 +83,7 @@ public class TbMemberPointsServiceImpl extends ServiceImpl<TbMemberPointsMapper,
if (entity == null) {
throw new BadRequestException("会员信息不存在");
}
if(entity.getAccountPoints() == null){
if (entity.getAccountPoints() == null) {
entity.setAccountPoints(0);
}
super.updateById(entity);
@ -108,9 +109,23 @@ public class TbMemberPointsServiceImpl extends ServiceImpl<TbMemberPointsMapper,
dto.setUnusableReason("商家未启用积分抵扣功能");
return dto;
}
dto.setMinDeductionPoints(basic.getMinDeductionPoint());
if (accountPoints == 0 || accountPoints < basic.getMinDeductionPoint()) {
dto.setUnusableReason("积分不足或小于最低使用门槛" + basic.getMinDeductionPoint());
if ("vip".equals(basic.getDeductionGroup()) && ObjectUtil.defaultIfNull(entity.getVip(), 0) != 1) {
dto.setUnusableReason("仅VIP用户可用");
return dto;
}
dto.setMinPaymentAmount(basic.getMinPaymentAmount());
dto.setOrderAmount(orderAmount);
if (NumberUtil.isLess(orderAmount, basic.getMinPaymentAmount())) {
dto.setUnusableReason(StrUtil.format("实付金额不足¥{}元,无法进行抵扣", basic.getMinPaymentAmount()));
return dto;
}
dto.setEquivalentPoints(basic.getEquivalentPoints());
// 最低抵扣积分 = 1元等值积分 = 1.0元
dto.setMinDeductionPoints(basic.getEquivalentPoints());
// 计算抵扣门槛=?
dto.setMinDeductionAmount(BigDecimal.ONE);
if (accountPoints == 0 || accountPoints < dto.getMinDeductionPoints()) {
dto.setUnusableReason("积分不足或小于最低使用门槛" + dto.getMinDeductionPoints());
return dto;
}
// 下单抵扣积分比例 1元=?积分
@ -120,26 +135,17 @@ public class TbMemberPointsServiceImpl extends ServiceImpl<TbMemberPointsMapper,
// 下单最高抵扣比例
BigDecimal maxDeductionRatio = basic.getMaxDeductionRatio();
// 计算订单最多可以抵扣多少元
BigDecimal orderYuan = NumberUtil.mul(orderAmount, NumberUtil.div(maxDeductionRatio, new BigDecimal("100")));
BigDecimal orderYuan = NumberUtil.roundDown(NumberUtil.mul(orderAmount, NumberUtil.div(maxDeductionRatio, new BigDecimal("100"))), 2);
// 积分余额足够
if (NumberUtil.isGreaterOrEqual(accountYuan, orderYuan)) {
dto.setMaxDeductionAmount(orderYuan);
} else {
dto.setMaxDeductionAmount(NumberUtil.roundDown(accountYuan, 2));
}
if (NumberUtil.isLess(dto.getMaxDeductionAmount(), new BigDecimal("0.01"))) {
dto.setUnusableReason("积分不足0.01元无法进行抵扣");
if (NumberUtil.isLess(dto.getMaxDeductionAmount(), BigDecimal.ONE)) {
dto.setUnusableReason("积分不足1元无法进行抵扣");
return dto;
}
// 计算抵扣门槛=?
BigDecimal minYuan = NumberUtil.div(basic.getMinDeductionPoint(), equivalentPoints);
if (NumberUtil.isLess(minYuan, new BigDecimal("0.01"))) {
dto.setMinDeductionAmount(new BigDecimal("0.01"));
} else {
dto.setMinDeductionAmount(NumberUtil.roundDown(minYuan, 2));
}
dto.setEquivalentPoints(equivalentPoints);
dto.setOrderAmount(orderAmount);
dto.setUsable(true);
// 计算最多可抵扣的积分
BigDecimal mul = NumberUtil.mul(dto.getMaxDeductionAmount(), equivalentPoints);
@ -178,13 +184,12 @@ public class TbMemberPointsServiceImpl extends ServiceImpl<TbMemberPointsMapper,
if (points > core.getMaxUsablePoints()) {
throw new BadRequestException(StrUtil.format("使用积分不能超过最大使用限制{}", core.getMaxUsablePoints()));
}
BigDecimal mul = NumberUtil.mul(new BigDecimal("0.01"), core.getEquivalentPoints());
int minPoints = NumberUtil.round(mul, 0, RoundingMode.CEILING).intValue();
if (points < minPoints) {
throw new BadRequestException(StrUtil.format("使用积分不能低于{}(0.01元)", minPoints));
}
BigDecimal money = NumberUtil.mul(points, NumberUtil.div(BigDecimal.ONE, core.getEquivalentPoints()));
return NumberUtil.roundDown(money, 2);
BigDecimal maxDeductionAmount = NumberUtil.roundDown(money, 2);
if (NumberUtil.isGreater(maxDeductionAmount, core.getMaxDeductionAmount())) {
return core.getMaxDeductionAmount();
}
return maxDeductionAmount;
}
@Override
@ -270,6 +275,17 @@ public class TbMemberPointsServiceImpl extends ServiceImpl<TbMemberPointsMapper,
if (enableRewards == 0) {
return;
}
String rewardsGroup = basicSetting.getRewardsGroup();
TbMemberPoints entity;
try {
entity = initMemberPoints(memberId);
} catch (Exception e) {
return;
}
Integer vip = entity.getVip();
if ("vip".equals(rewardsGroup) && ObjectUtil.defaultIfNull(vip, 0) != 1) {
return;
}
BigDecimal consumeAmount = basicSetting.getConsumeAmount();
if (consumeAmount == null) {
return;

View File

@ -1,6 +1,7 @@
package cn.ysk.cashier.mybatis.service.impl;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mybatis.entity.TbPointsBasicSetting;
import cn.ysk.cashier.mybatis.mapper.TbPointsBasicSettingMapper;
@ -10,6 +11,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
/**
@ -26,18 +28,27 @@ public class TbPointsBasicSettingServiceImpl extends ServiceImpl<TbPointsBasicSe
@Transactional(rollbackFor = Exception.class)
public boolean save(TbPointsBasicSetting entity) {
try {
Assert.notNull(entity.getShopId(), "{}({})不能为空", "店铺id","shopId");
Assert.notNull(entity.getEnableRewards(), "{}({})不能为空", "开启消费赠送积分","enableRewards");
Assert.notNull(entity.getConsumeAmount(), "{}({})不能为空", "每消费xx元赠送1积分","consumeAmount");
Assert.notNull(entity.getEnableDeduction(), "{}({})不能为空", "开启下单积分抵扣","enableDeduction");
Assert.notNull(entity.getMinDeductionPoint(), "{}({})不能为空", "下单积分抵扣门槛","minDeductionPoint");
Assert.notNull(entity.getMaxDeductionRatio(), "{}({})不能为空", "下单最高抵扣比例","maxDeductionRatio");
Assert.notNull(entity.getEquivalentPoints(), "{}({})不能为空", "下单抵扣积分比例","equivalentPoints");
Assert.notNull(entity.getEnablePointsMall(), "{}({})不能为空", "开启积分商城","enablePointsMall");
Assert.notEmpty(entity.getBrowseMode(), "{}({})不能为空", "浏览模式","browseMode");
Assert.notNull(entity.getShopId(), "{}({})不能为空", "店铺id", "shopId");
Assert.notNull(entity.getEnableRewards(), "{}({})不能为空", "开启消费赠送积分", "enableRewards");
Assert.notNull(entity.getConsumeAmount(), "{}({})不能为空", "每消费xx元赠送1积分", "consumeAmount");
Assert.notNull(entity.getEnableDeduction(), "{}({})不能为空", "开启下单积分抵扣", "enableDeduction");
Assert.notNull(entity.getMinPaymentAmount(), "{}({})不能为空", "下单实付抵扣门槛", "minPaymentAmount");
Assert.notNull(entity.getMaxDeductionRatio(), "{}({})不能为空", "下单最高抵扣比例", "maxDeductionRatio");
Assert.notNull(entity.getEquivalentPoints(), "{}({})不能为空", "下单抵扣积分比例", "equivalentPoints");
Assert.notNull(entity.getEnablePointsMall(), "{}({})不能为空", "开启积分商城", "enablePointsMall");
Assert.notEmpty(entity.getBrowseMode(), "{}({})不能为空", "浏览模式", "browseMode");
} catch (IllegalArgumentException e) {
throw new BadRequestException(e.getMessage());
}
if (NumberUtil.isLessOrEqual(entity.getMinPaymentAmount(),BigDecimal.ZERO)) {
throw new BadRequestException("下单实付抵扣门槛不能小于等于0");
}
if (NumberUtil.isLessOrEqual(entity.getMaxDeductionRatio(), BigDecimal.ZERO)) {
throw new BadRequestException("下单最高抵扣比例不能小于等于0");
}
if (NumberUtil.isGreater(entity.getMaxDeductionRatio(), new BigDecimal("100"))) {
throw new BadRequestException("下单最高抵扣比例不能大于100");
}
entity.setCreateTime(new Date());
super.remove(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, entity.getShopId()));
super.save(entity);

View File

@ -2,22 +2,29 @@ package cn.ysk.cashier.mybatis.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
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.util.IdUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mybatis.entity.*;
import cn.ysk.cashier.mybatis.entity.TbMemberPoints;
import cn.ysk.cashier.mybatis.entity.TbMemberPointsLog;
import cn.ysk.cashier.mybatis.entity.TbPointsExchangeRecord;
import cn.ysk.cashier.mybatis.entity.TbPointsGoodsSetting;
import cn.ysk.cashier.mybatis.mapper.*;
import cn.ysk.cashier.mybatis.service.TbPointsExchangeRecordService;
import cn.ysk.cashier.pojo.shop.TbMerchantThirdApply;
import cn.ysk.cashier.pojo.shop.TbShopInfo;
import cn.ysk.cashier.repository.shop.TbMerchantThirdApplyRepository;
import cn.ysk.cashier.thirdpay.resp.OrderReturnResp;
import cn.ysk.cashier.thirdpay.resp.PublicResp;
import cn.ysk.cashier.thirdpay.service.ThirdPayService;
import cn.ysk.cashier.utils.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -36,6 +43,17 @@ import java.util.Map;
@Service
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;
@Resource
private TbPointsBasicSettingMapper tbPointsBasicSettingMapper;
@ -48,6 +66,14 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
@Resource
private TbMemberPointsLogMapper tbMemberPointsLogMapper;
@Resource
private MpShopInfoMapper mpShopInfoMapper;
@Resource
private TbMerchantThirdApplyRepository tbMerchantThirdApplyRepository;
@Resource
private ThirdPayService thirdPayService;
private LambdaQueryWrapper<TbPointsExchangeRecord> getWrapper(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
String keywords = mapProxy.getStr("keywords");
@ -89,6 +115,7 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
}
@Override
@Transactional(rollbackFor = Exception.class)
public void checkout(String couponCode) {
if (StrUtil.isBlank(couponCode)) {
throw new BadRequestException("兑换券券码不能为空");
@ -100,92 +127,121 @@ public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExcha
entity.setStatus("done");
entity.setUpdateTime(new Date());
super.updateById(entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public TbPointsExchangeRecord exchange(TbPointsExchangeRecord record) {
try {
Assert.notNull(record.getShopId(), "{}({})不能为空", "店铺id", "shopId");
Assert.notNull(record.getPointsGoodsId(), "{}({})不能为空", "积分商品id", "pointsGoodsId");
Assert.notEmpty(record.getPickupMethod(), "{}({})不能为空", "领取方式", "pickupMethod");
Assert.notNull(record.getMemberId(), "{}({})不能为空", "会员id", "memberId");
Assert.notEmpty(record.getMemberName(), "{}({})不能为空", "会员名称", "memberName");
Assert.notEmpty(record.getMobile(), "{}({})不能为空", "手机号码", "mobile");
} catch (IllegalArgumentException e) {
throw new BadRequestException(e.getMessage());
}
TbPointsBasicSetting basic = tbPointsBasicSettingMapper.selectOne(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, record.getShopId()));
if (basic == null) {
throw new BadRequestException("未配置积分锁客基本设置");
}
if (basic.getEnablePointsMall() != 1) {
throw new BadRequestException("积分商城未开启");
}
TbPointsGoodsSetting goods = tbPointsGoodsSettingMapper.selectById(record.getPointsGoodsId());
TbPointsGoodsSetting goods = tbPointsGoodsSettingMapper.selectById(entity.getPointsGoodsId());
if (goods == null) {
throw new BadRequestException("兑换的商品信息不存在");
throw new BadRequestException("积分商品不存在");
}
if (goods.getDelFlag() == 1) {
throw new BadRequestException("兑换的商品信息不存在");
}
record.setPointsGoodsName(goods.getGoodsName());
record.setGoodsImageUrl(goods.getGoodsImageUrl());
Integer status = goods.getStatus();
if (status != 1) {
throw new BadRequestException("兑换的商品已下架");
}
Integer quantity = goods.getQuantity();
if (quantity <= 0) {
throw new BadRequestException("兑换的商品库存不足");
}
TbMemberPoints memberPoints = tbMemberPointsMapper.selectOne(Wrappers.<TbMemberPoints>lambdaQuery().eq(TbMemberPoints::getMemberId, record.getMemberId()));
if (memberPoints == null) {
throw new BadRequestException("该会员积分不足无法兑换这个商品");
}
Integer accountPoints = memberPoints.getAccountPoints();
Integer requiredPoints = goods.getRequiredPoints();
if (accountPoints < requiredPoints) {
throw new BadRequestException("该会员积分不足无法兑换这个商品");
}
BigDecimal extraPrice = goods.getExtraPrice();
record.setExtraPaymentAmount(extraPrice);
record.setSpendPoints(requiredPoints);
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.setCreateTime(new Date());
// 生成订单
super.save(record);
// 扣减积分
memberPoints.setAccountPoints(accountPoints - requiredPoints);
memberPoints.setLastPointsChangeTime(new Date());
memberPoints.setLastFloatPoints(-requiredPoints);
tbMemberPointsMapper.updateById(memberPoints);
// 扣减库存
goods.setQuantity(quantity - 1);
goods.setUpdateTime(new Date());
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.setFloatType("subtract");
log.setFloatPoints(-requiredPoints);
log.setCreateTime(new Date());
tbMemberPointsLogMapper.insert(log);
// 更新累计兑换数量
goods.setTotalExchangeCount(goods.getTotalExchangeCount() + 1);
goods.setUpdateTime(new Date());
tbPointsGoodsSettingMapper.updateById(goods);
return record;
}
@Override
public void cancel(TbPointsExchangeRecord record) {
if (record.getId() == null) {
throw new BadRequestException("订单ID不能为空");
}
TbPointsExchangeRecord entity = super.getById(record.getId());
if (entity == null) {
throw new BadRequestException("订单不存在");
}
if (!"unpaid".equals(entity.getStatus())) {
throw new BadRequestException("当前订单状态不支持取消");
}
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 BadRequestException("订单ID不能为空");
}
TbPointsExchangeRecord entity = super.getById(record.getId());
if (entity == null) {
throw new BadRequestException("订单不存在");
}
if (!"waiting".equals(entity.getStatus())) {
throw new BadRequestException("当前订单状态不支持退款");
}
// 先退积分
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 BadRequestException("会员信息不存在");
}
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 BadRequestException("积分商品不存在");
}
goods.setQuantity(goods.getQuantity() + 1);
goods.setUpdateTime(new Date());
tbPointsGoodsSettingMapper.updateById(goods);
// 记录积分浮动流水
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;
}
// 需要额外支付
TbShopInfo shopInfo = mpShopInfoMapper.selectById(entity.getShopId());
if (shopInfo == null) {
throw new BadRequestException("店铺信息不存在");
}
TbMerchantThirdApply thirdApply = tbMerchantThirdApplyRepository.getById(Integer.valueOf(shopInfo.getMerchantId()));
if (thirdApply == null) {
throw new BadRequestException("支付通道不存在");
}
if ("alipay".equalsIgnoreCase(entity.getPayType()) && StrUtil.isBlank(thirdApply.getAlipaySmallAppid())) {
throw new BadRequestException("店铺未配置支付宝小程序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 BadRequestException(StrUtil.format("发起退款失败:{}", e.getMessage()));
}
if (publicResp == null) {
throw new BadRequestException("发起退款失败:无响应");
}
if (!"000000".equals(publicResp.getCode())) {
throw new BadRequestException(publicResp.getMsg());
}
OrderReturnResp returnResp = publicResp.getObjData();
if (!"SUCCESS".equals(returnResp.getState())) {
throw new BadRequestException(StrUtil.format("退款失败原因:{}", returnResp.getState()));
}
}
@Override