积分模块相关代码

This commit is contained in:
谭凯凯
2024-10-31 09:32:40 +08:00
committed by Tankaikai
parent 9e70c63407
commit 1e9d7c84c3
31 changed files with 1790 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
package com.chaozhanggui.system.cashierservice.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chaozhanggui.system.cashierservice.entity.TbMemberPointsLog;
import com.github.pagehelper.PageInfo;
import java.util.Map;
/**
* 会员积分变动记录
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
public interface TbMemberPointsLogService extends IService<TbMemberPointsLog> {
PageInfo<TbMemberPointsLog> page(Map<String, Object> params);
}

View File

@@ -0,0 +1,100 @@
package com.chaozhanggui.system.cashierservice.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chaozhanggui.system.cashierservice.entity.TbMemberPoints;
import com.chaozhanggui.system.cashierservice.entity.dto.OrderDeductionPointsDTO;
import com.github.pagehelper.PageInfo;
import java.math.BigDecimal;
import java.util.Map;
/**
* 会员积分
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
public interface TbMemberPointsService extends IService<TbMemberPoints> {
/**
* 会员积分分页
*
* @param params
* @return
*/
PageInfo<TbMemberPoints> page(Map<String, Object> params);
/**
* 获取会员积分等信息
*
* @param memberId 会员id
* @return
*/
TbMemberPoints getMemberPoints(Long memberId);
/**
* 初始化会员积分
*
* @param memberId 会员id
* @return
*/
TbMemberPoints initMemberPoints(Long memberId);
/**
* 根据会员id及订单金额计算可抵扣积分及可抵扣金额
*
* @param memberId 会员id
* @param orderAmount 订单金额
* @return
*/
OrderDeductionPointsDTO getMemberUsablePoints(Long memberId, BigDecimal orderAmount);
/**
* 根据抵扣金额计算抵扣积分
*
* @param memberId 会员id
* @param orderAmount 订单金额
* @param deductionAmount 抵扣金额
*/
int calcUsedPoints(Long memberId, BigDecimal orderAmount, BigDecimal deductionAmount);
/**
* 根据抵扣积分计算抵扣金额
*
* @param memberId 会员id
* @param orderAmount 订单金额
* @param points 抵扣积分
*/
BigDecimal calcDeductionAmount(Long memberId, BigDecimal orderAmount, int points);
/**
* 扣除积分
*
* @param memberId 会员id
* @param points 积分
* @param content 摘要信息(如:兑换积分商品/积分抵扣账单/消费赠送积分/新会员送积分/储值赠送积分)
* @param orderId 订单id可以为空
* @throws Exception
*/
boolean deductPoints(Long memberId, int points, String content, Long orderId);
/**
* 追加积分
*
* @param memberId 会员id
* @param points 积分
* @param content 摘要信息(如:兑换积分商品/积分抵扣账单/消费赠送积分/新会员送积分/储值赠送积分)
* @param orderId 订单id可以为空
* @throws Exception
*/
boolean addPoints(Long memberId, int points, String content, Long orderId);
/**
* 消费赠送积分
*
* @param memberId 会员id
* @param orderId 订单id
* @throws Exception
*/
void consumeAwardPoints(Long memberId, Long orderId);
}

View File

@@ -0,0 +1,16 @@
package com.chaozhanggui.system.cashierservice.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chaozhanggui.system.cashierservice.entity.TbPointsBasicSetting;
/**
* 积分基本设置
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
public interface TbPointsBasicSettingService extends IService<TbPointsBasicSetting> {
boolean save(TbPointsBasicSetting entity);
TbPointsBasicSetting getByShopId(Long shopId);
}

View File

@@ -0,0 +1,26 @@
package com.chaozhanggui.system.cashierservice.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chaozhanggui.system.cashierservice.entity.TbPointsExchangeRecord;
import com.github.pagehelper.PageInfo;
import java.util.Map;
/**
* 积分兑换记录
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
public interface TbPointsExchangeRecordService extends IService<TbPointsExchangeRecord> {
PageInfo<TbPointsExchangeRecord> page(Map<String, Object> params);
TbPointsExchangeRecord get(Long id);
void checkout(String couponCode);
TbPointsExchangeRecord exchange(TbPointsExchangeRecord record);
Map<String, Object> total(Map<String, Object> params);
}

View File

@@ -0,0 +1,23 @@
package com.chaozhanggui.system.cashierservice.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chaozhanggui.system.cashierservice.entity.TbPointsGoodsSetting;
import com.github.pagehelper.PageInfo;
import java.util.Map;
/**
* 积分商品设置
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
public interface TbPointsGoodsSettingService extends IService<TbPointsGoodsSetting> {
PageInfo<TbPointsGoodsSetting> page(Map<String, Object> params);
boolean save(TbPointsGoodsSetting entity);
boolean update(TbPointsGoodsSetting dto);
}

View File

@@ -0,0 +1,60 @@
package com.chaozhanggui.system.cashierservice.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapProxy;
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.entity.TbMemberPointsLog;
import com.chaozhanggui.system.cashierservice.mapper.TbMemberPointsLogMapper;
import com.chaozhanggui.system.cashierservice.service.TbMemberPointsLogService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* 会员积分变动记录
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
@Service
public class TbMemberPointsLogServiceImpl extends ServiceImpl<TbMemberPointsLogMapper, TbMemberPointsLog> implements TbMemberPointsLogService {
private LambdaQueryWrapper<TbMemberPointsLog> getWrapper(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
String beginDate = mapProxy.getStr("beginDate");
String endDate = mapProxy.getStr("endDate");
TbMemberPointsLog param = BeanUtil.toBean(params, TbMemberPointsLog.class);
LambdaQueryWrapper<TbMemberPointsLog> wrapper = Wrappers.lambdaQuery();
wrapper.eq(TbMemberPointsLog::getShopId, param.getShopId());
wrapper.like(StrUtil.isNotEmpty(param.getMemberName()), TbMemberPointsLog::getMemberName, param.getMemberName());
wrapper.like(StrUtil.isNotEmpty(param.getMobile()), TbMemberPointsLog::getMobile, param.getMobile());
wrapper.like(StrUtil.isNotEmpty(param.getContent()), TbMemberPointsLog::getContent, param.getContent());
wrapper.eq(StrUtil.isNotEmpty(param.getFloatType()), TbMemberPointsLog::getFloatType, param.getFloatType());
wrapper.eq(StrUtil.isNotEmpty(param.getOrderNo()), TbMemberPointsLog::getOrderNo, param.getOrderNo());
if (StrUtil.isNotEmpty(beginDate)) {
wrapper.apply("create_time >= str_to_date({0}, '%Y-%m-%d %H:%i:%s')", beginDate + " 00:00:00");
}
if (StrUtil.isNotEmpty(endDate)) {
wrapper.apply("create_time <= str_to_date({0}, '%Y-%m-%d %H:%i:%s')", endDate + " 23:59:59");
}
wrapper.orderByDesc(TbMemberPointsLog::getId);
return wrapper;
}
@Override
public PageInfo<TbMemberPointsLog> page(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
int pageNum = mapProxy.getInt("page", 1);
int pageSize = mapProxy.getInt("size", 10);
LambdaQueryWrapper<TbMemberPointsLog> wrapper = getWrapper(params);
PageInfo<TbMemberPointsLog> page = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> baseMapper.selectList(wrapper));
//Page<TbMemberPointsLog> page = super.page(new Page<>(pageNum, pageSize), wrapper);
return page;
}
}

View File

@@ -0,0 +1,288 @@
package com.chaozhanggui.system.cashierservice.service.impl;
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.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.TbOrderInfoMapper;
import com.chaozhanggui.system.cashierservice.dao.TbShopUserMapper;
import com.chaozhanggui.system.cashierservice.entity.TbMemberPoints;
import com.chaozhanggui.system.cashierservice.entity.TbMemberPointsLog;
import com.chaozhanggui.system.cashierservice.entity.TbOrderInfo;
import com.chaozhanggui.system.cashierservice.entity.TbPointsBasicSetting;
import com.chaozhanggui.system.cashierservice.entity.dto.OrderDeductionPointsDTO;
import com.chaozhanggui.system.cashierservice.exception.MsgException;
import com.chaozhanggui.system.cashierservice.mapper.TbMemberPointsLogMapper;
import com.chaozhanggui.system.cashierservice.mapper.TbMemberPointsMapper;
import com.chaozhanggui.system.cashierservice.mapper.TbPointsBasicSettingMapper;
import com.chaozhanggui.system.cashierservice.service.TbMemberPointsService;
import com.chaozhanggui.system.cashierservice.service.TbPointsBasicSettingService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.Map;
/**
* 会员积分
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
@Service
public class TbMemberPointsServiceImpl extends ServiceImpl<TbMemberPointsMapper, TbMemberPoints> implements TbMemberPointsService {
@Resource
private TbMemberPointsLogMapper tbMemberPointsLogMapper;
@Resource
private TbPointsBasicSettingMapper tbPointsBasicSettingMapper;
@Resource
private TbShopUserMapper tbShopUserMapper;
@Resource
private TbOrderInfoMapper tbOrderInfoMapper;
@Resource
private TbPointsBasicSettingService tbPointsBasicSettingService;
private LambdaQueryWrapper<TbMemberPoints> getWrapper(Map<String, Object> params) {
//MapProxy mapProxy = MapProxy.create(params);
TbMemberPoints param = BeanUtil.toBean(params, TbMemberPoints.class);
LambdaQueryWrapper<TbMemberPoints> wrapper = Wrappers.lambdaQuery();
wrapper.eq(TbMemberPoints::getShopId, param.getShopId());
wrapper.like(StrUtil.isNotEmpty(param.getMemberName()), TbMemberPoints::getMemberName, param.getMemberName());
wrapper.like(StrUtil.isNotEmpty(param.getMobile()), TbMemberPoints::getMobile, param.getMobile());
wrapper.orderByDesc(TbMemberPoints::getId);
return wrapper;
}
@Override
public PageInfo<TbMemberPoints> page(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
int pageNum = mapProxy.getInt("page", 1);
int pageSize = mapProxy.getInt("size", 10);
LambdaQueryWrapper<TbMemberPoints> wrapper = getWrapper(params);
PageInfo<TbMemberPoints> page = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> baseMapper.selectList(wrapper));
//Page<TbMemberPoints> page = super.page(new Page<>(pageNum, pageSize), wrapper);
return page;
}
@Override
public TbMemberPoints getMemberPoints(Long memberId) {
return initMemberPoints(memberId);
}
@Override
public TbMemberPoints initMemberPoints(Long memberId) {
TbMemberPoints entity = super.getOne(Wrappers.<TbMemberPoints>lambdaQuery().eq(TbMemberPoints::getMemberId, memberId));
if (entity == null) {
throw new MsgException("会员信息不存在");
}
if(entity.getAccountPoints() == null){
entity.setAccountPoints(0);
}
super.updateById(entity);
return entity;
}
@Override
public OrderDeductionPointsDTO getMemberUsablePoints(Long memberId, BigDecimal orderAmount) {
TbMemberPoints entity = initMemberPoints(memberId);
Long shopId = entity.getShopId();
Integer accountPoints = entity.getAccountPoints();
OrderDeductionPointsDTO dto = new OrderDeductionPointsDTO();
dto.setAccountPoints(accountPoints);
dto.setUsable(false);
dto.setMaxDeductionAmount(BigDecimal.ZERO);
dto.setMinDeductionAmount(BigDecimal.ZERO);
TbPointsBasicSetting basic = tbPointsBasicSettingMapper.selectOne(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, shopId));
if (basic == null) {
dto.setUnusableReason("商家未启用积分抵扣功能");
return dto;
}
if (basic.getEnableDeduction() == 0) {
dto.setUnusableReason("商家未启用积分抵扣功能");
return dto;
}
dto.setMinDeductionPoints(basic.getMinDeductionPoint());
if (accountPoints == 0 || accountPoints < basic.getMinDeductionPoint()) {
dto.setUnusableReason("积分不足或小于最低使用门槛" + basic.getMinDeductionPoint());
return dto;
}
// 下单抵扣积分比例 1元=?积分
Integer equivalentPoints = basic.getEquivalentPoints();
// 计算账户积分=?元
BigDecimal accountYuan = NumberUtil.div(accountPoints, equivalentPoints);
// 下单最高抵扣比例
BigDecimal maxDeductionRatio = basic.getMaxDeductionRatio();
// 计算订单最多可以抵扣多少元
BigDecimal orderYuan = NumberUtil.mul(orderAmount, NumberUtil.div(maxDeductionRatio, new BigDecimal("100")));
// 积分余额足够
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元,无法进行抵扣");
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);
BigDecimal round = NumberUtil.round(mul, 0, RoundingMode.CEILING);
dto.setMaxUsablePoints(round.intValue());
return dto;
}
@Override
public int calcUsedPoints(Long memberId, BigDecimal orderAmount, BigDecimal deductionAmount) {
OrderDeductionPointsDTO core = getMemberUsablePoints(memberId, orderAmount);
if (!core.getUsable()) {
throw new MsgException(core.getUnusableReason());
}
if (NumberUtil.isGreater(deductionAmount, core.getMaxDeductionAmount())) {
throw new MsgException(StrUtil.format("抵扣金额不能超过最大抵扣金额{}元", core.getMaxDeductionAmount()));
}
if (NumberUtil.isGreater(deductionAmount, orderAmount)) {
throw new MsgException(StrUtil.format("抵扣金额不能超过订单金额{}元", orderAmount));
}
// 计算可抵扣的积分
BigDecimal mul = NumberUtil.mul(deductionAmount, core.getEquivalentPoints());
BigDecimal round = NumberUtil.round(mul, 0, RoundingMode.CEILING);
return round.intValue();
}
@Override
public BigDecimal calcDeductionAmount(Long memberId, BigDecimal orderAmount, int points) {
OrderDeductionPointsDTO core = getMemberUsablePoints(memberId, orderAmount);
if (!core.getUsable()) {
throw new MsgException(core.getUnusableReason());
}
if (points < core.getMinDeductionPoints()) {
throw new MsgException(StrUtil.format("使用积分不能低于使用门槛(每次最少使用{}积分)", core.getMinDeductionPoints()));
}
if (points > core.getMaxUsablePoints()) {
throw new MsgException(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 MsgException(StrUtil.format("使用积分不能低于{}(0.01元)", minPoints));
}
BigDecimal money = NumberUtil.mul(points, NumberUtil.div(BigDecimal.ONE, core.getEquivalentPoints()));
return NumberUtil.roundDown(money, 2);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deductPoints(Long memberId, int points, String content, Long orderId) {
TbMemberPoints entity = initMemberPoints(memberId);
// 扣除账户积分
entity.setAccountPoints(entity.getAccountPoints() - points);
entity.setLastPointsChangeTime(new Date());
entity.setLastFloatPoints(-points);
// 记录积分变动记录
TbMemberPointsLog log = new TbMemberPointsLog();
log.setShopId(entity.getShopId());
log.setMemberId(entity.getMemberId());
log.setMemberName(entity.getMemberName());
log.setAvatarUrl(entity.getAvatarUrl());
log.setMobile(entity.getMobile());
log.setContent(content);
log.setFloatType("subtract");
log.setFloatPoints(-points);
log.setCreateTime(new Date());
// 有关联订单的需要回置订单表的相关积分使用字段
if (orderId != null) {
TbOrderInfo orderInfo = tbOrderInfoMapper.selectByPrimaryKey(Convert.toInt(orderId));
if (orderInfo != null) {
log.setOrderNo(orderInfo.getOrderNo());
// TODO 是否需要回执“使用的积分数量(points_num)”和“积分抵扣金额(points_discount_amount)”,目前不清楚是创建订单的时候置入还是支付完成后回调时置入需要商议后决定
}
}
super.updateById(entity);
tbMemberPointsLogMapper.insert(log);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addPoints(Long memberId, int points, String content, Long orderId) {
TbMemberPoints entity = initMemberPoints(memberId);
// 增加账户积分
entity.setAccountPoints(entity.getAccountPoints() + points);
entity.setLastPointsChangeTime(new Date());
entity.setLastFloatPoints(points);
// 记录积分变动记录
TbMemberPointsLog log = new TbMemberPointsLog();
log.setShopId(entity.getShopId());
log.setMemberId(entity.getMemberId());
log.setMemberName(entity.getMemberName());
log.setAvatarUrl(entity.getAvatarUrl());
log.setMobile(entity.getMobile());
log.setContent(content);
log.setFloatType("add");
log.setFloatPoints(points);
log.setCreateTime(new Date());
// 有关联订单的需要回置订单表的相关积分使用字段
if (orderId != null) {
TbOrderInfo orderInfo = tbOrderInfoMapper.selectByPrimaryKey(Convert.toInt(orderId));
if (orderInfo != null) {
log.setOrderNo(orderInfo.getOrderNo());
}
}
super.updateById(entity);
tbMemberPointsLogMapper.insert(log);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void consumeAwardPoints(Long memberId, Long orderId) {
TbOrderInfo orderInfo = tbOrderInfoMapper.selectByPrimaryKey(Convert.toInt(orderId));
if (orderInfo == null) {
throw new MsgException("订单不存在");
}
BigDecimal payAmount = orderInfo.getPayAmount();
if (NumberUtil.isLessOrEqual(payAmount, BigDecimal.ZERO)) {
return;
}
TbPointsBasicSetting basicSetting = tbPointsBasicSettingService.getByShopId(Convert.toLong(orderInfo.getShopId()));
if (basicSetting == null) {
return;
}
Integer enableRewards = basicSetting.getEnableRewards();
if (enableRewards == 0) {
return;
}
BigDecimal consumeAmount = basicSetting.getConsumeAmount();
if (consumeAmount == null) {
return;
}
if (NumberUtil.isLessOrEqual(consumeAmount, BigDecimal.ZERO)) {
return;
}
BigDecimal awardPoints = NumberUtil.roundDown(NumberUtil.div(payAmount, consumeAmount), 0);
addPoints(memberId, awardPoints.intValue(), StrUtil.format("消费¥{}送{}积分", payAmount, awardPoints.intValue()), orderId);
}
}

View File

@@ -0,0 +1,51 @@
package com.chaozhanggui.system.cashierservice.service.impl;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chaozhanggui.system.cashierservice.entity.TbPointsBasicSetting;
import com.chaozhanggui.system.cashierservice.exception.MsgException;
import com.chaozhanggui.system.cashierservice.mapper.TbPointsBasicSettingMapper;
import com.chaozhanggui.system.cashierservice.service.TbPointsBasicSettingService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* 积分基本设置
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
@Service
public class TbPointsBasicSettingServiceImpl extends ServiceImpl<TbPointsBasicSettingMapper, TbPointsBasicSetting> implements TbPointsBasicSettingService {
@Override
@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");
} catch (IllegalArgumentException e) {
throw new MsgException(e.getMessage());
}
entity.setCreateTime(new Date());
super.remove(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, entity.getShopId()));
super.save(entity);
return true;
}
@Override
public TbPointsBasicSetting getByShopId(Long shopId) {
return super.getOne(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, shopId));
}
}

View File

@@ -0,0 +1,195 @@
package com.chaozhanggui.system.cashierservice.service.impl;
import cn.hutool.core.bean.BeanUtil;
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.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.entity.*;
import com.chaozhanggui.system.cashierservice.exception.MsgException;
import com.chaozhanggui.system.cashierservice.mapper.*;
import com.chaozhanggui.system.cashierservice.service.TbPointsExchangeRecordService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 积分兑换记录
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
@Service
public class TbPointsExchangeRecordServiceImpl extends ServiceImpl<TbPointsExchangeRecordMapper, TbPointsExchangeRecord> implements TbPointsExchangeRecordService {
@Resource
private TbPointsBasicSettingMapper tbPointsBasicSettingMapper;
@Resource
private TbPointsGoodsSettingMapper tbPointsGoodsSettingMapper;
@Resource
private TbMemberPointsMapper tbMemberPointsMapper;
@Resource
private TbMemberPointsLogMapper tbMemberPointsLogMapper;
private LambdaQueryWrapper<TbPointsExchangeRecord> getWrapper(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
String keywords = mapProxy.getStr("keywords");
String beginDate = mapProxy.getStr("beginDate");
String endDate = mapProxy.getStr("endDate");
TbPointsExchangeRecord param = BeanUtil.toBean(params, TbPointsExchangeRecord.class);
LambdaQueryWrapper<TbPointsExchangeRecord> wrapper = Wrappers.lambdaQuery();
wrapper.eq(TbPointsExchangeRecord::getShopId, param.getShopId());
wrapper.eq(StrUtil.isNotEmpty(param.getPickupMethod()), TbPointsExchangeRecord::getPickupMethod, param.getPickupMethod());
wrapper.eq(StrUtil.isNotEmpty(param.getStatus()), TbPointsExchangeRecord::getStatus, param.getStatus());
wrapper.eq(param.getMemberId() != null, TbPointsExchangeRecord::getMemberId, param.getMemberId());
if (StrUtil.isNotEmpty(keywords)) {
wrapper.nested(i -> i.like(TbPointsExchangeRecord::getOrderNo, keywords).or().like(TbPointsExchangeRecord::getCouponCode, keywords));
}
if (StrUtil.isNotEmpty(beginDate)) {
wrapper.apply("create_time >= str_to_date({0}, '%Y-%m-%d %H:%i:%s')", beginDate + " 00:00:00");
}
if (StrUtil.isNotEmpty(endDate)) {
wrapper.apply("create_time <= str_to_date({0}, '%Y-%m-%d %H:%i:%s')", endDate + " 23:59:59");
}
wrapper.orderByDesc(TbPointsExchangeRecord::getId);
return wrapper;
}
@Override
public PageInfo<TbPointsExchangeRecord> page(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
int pageNum = mapProxy.getInt("page", 1);
int pageSize = mapProxy.getInt("size", 10);
LambdaQueryWrapper<TbPointsExchangeRecord> wrapper = getWrapper(params);
PageInfo<TbPointsExchangeRecord> page = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> baseMapper.selectList(wrapper));
//Page<TbPointsExchangeRecord> page = super.page(new Page<>(pageNum, pageSize), wrapper);
return page;
}
@Override
public TbPointsExchangeRecord get(Long id) {
return super.getById(id);
}
@Override
public void checkout(String couponCode) {
if (StrUtil.isBlank(couponCode)) {
throw new MsgException("兑换券券码不能为空");
}
TbPointsExchangeRecord entity = super.getOne(Wrappers.<TbPointsExchangeRecord>lambdaQuery().eq(TbPointsExchangeRecord::getCouponCode, couponCode));
if (entity == null) {
throw new MsgException("兑换券券码无效");
}
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 MsgException(e.getMessage());
}
TbPointsBasicSetting basic = tbPointsBasicSettingMapper.selectOne(Wrappers.<TbPointsBasicSetting>lambdaQuery().eq(TbPointsBasicSetting::getShopId, record.getShopId()));
if (basic == null) {
throw new MsgException("未配置积分锁客基本设置");
}
if (basic.getEnablePointsMall() != 1) {
throw new MsgException("积分商城未开启");
}
TbPointsGoodsSetting goods = tbPointsGoodsSettingMapper.selectById(record.getPointsGoodsId());
if (goods == null) {
throw new MsgException("兑换的商品信息不存在");
}
record.setPointsGoodsName(goods.getGoodsName());
record.setGoodsImageUrl(goods.getGoodsImageUrl());
Integer status = goods.getStatus();
if (status != 1) {
throw new MsgException("兑换的商品已下架");
}
Integer quantity = goods.getQuantity();
if (quantity <= 0) {
throw new MsgException("兑换的商品库存不足");
}
TbMemberPoints memberPoints = tbMemberPointsMapper.selectOne(Wrappers.<TbMemberPoints>lambdaQuery().eq(TbMemberPoints::getMobile, record.getMobile()));
if (memberPoints == null) {
throw new MsgException("该会员积分不足无法兑换这个商品");
}
Integer accountPoints = memberPoints.getAccountPoints();
Integer requiredPoints = goods.getRequiredPoints();
if (accountPoints < requiredPoints) {
throw new MsgException("该会员积分不足无法兑换这个商品");
}
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);
return record;
}
@Override
public Map<String, Object> total(Map<String, Object> params) {
LambdaQueryWrapper<TbPointsExchangeRecord> wrapper = getWrapper(params);
wrapper.select(TbPointsExchangeRecord::getCount, TbPointsExchangeRecord::getTotalAmount);
TbPointsExchangeRecord summary = baseMapper.selectOne(wrapper);
Map<String, Object> result = new HashMap<>(2);
result.put("count", summary.getCount());
result.put("totalAmount", NumberUtil.null2Zero(summary.getTotalAmount()));
return result;
}
}

View File

@@ -0,0 +1,95 @@
package com.chaozhanggui.system.cashierservice.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapProxy;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chaozhanggui.system.cashierservice.entity.TbPointsGoodsSetting;
import com.chaozhanggui.system.cashierservice.exception.MsgException;
import com.chaozhanggui.system.cashierservice.mapper.TbPointsGoodsSettingMapper;
import com.chaozhanggui.system.cashierservice.service.TbPointsGoodsSettingService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.Map;
/**
* 积分商品设置
*
* @author Tankaikai tankaikai@aliyun.com
* @since 2.0 2024-10-25
*/
@Service
public class TbPointsGoodsSettingServiceImpl extends ServiceImpl<TbPointsGoodsSettingMapper, TbPointsGoodsSetting> implements TbPointsGoodsSettingService {
@Override
public PageInfo<TbPointsGoodsSetting> page(Map<String, Object> params) {
MapProxy mapProxy = MapProxy.create(params);
int pageNum = mapProxy.getInt("page", 1);
int pageSize = mapProxy.getInt("size", 10);
TbPointsGoodsSetting param = BeanUtil.toBean(params, TbPointsGoodsSetting.class);
Page<TbPointsGoodsSetting> pg = new Page<>(pageNum, pageSize);
pg.addOrder(OrderItem.desc("sort"));
LambdaQueryWrapper<TbPointsGoodsSetting> wrapper = Wrappers.<TbPointsGoodsSetting>lambdaQuery()
.eq(TbPointsGoodsSetting::getShopId, param.getShopId())
.like(StrUtil.isNotEmpty(param.getGoodsName()), TbPointsGoodsSetting::getGoodsName, param.getGoodsName())
.like(StrUtil.isNotEmpty(param.getGoodsCategory()), TbPointsGoodsSetting::getGoodsCategory, param.getGoodsCategory())
.eq(param.getStatus() != null, TbPointsGoodsSetting::getStatus, param.getStatus())
.orderByDesc(TbPointsGoodsSetting::getId);
PageInfo<TbPointsGoodsSetting> page = PageHelper.startPage(pageNum, pageSize,"sort desc").doSelectPageInfo(() -> baseMapper.selectList(wrapper));
return page;
}
@Override
public boolean save(TbPointsGoodsSetting entity) {
try {
Assert.notNull(entity.getShopId(), "{}({})不能为空", "店铺id", "shopId");
Assert.notEmpty(entity.getGoodsCategory(), "{}({})不能为空", "商品类型", "goodsCategory");
Assert.notEmpty(entity.getGoodsName(), "{}({})不能为空", "商品名称", "goodsName");
//Assert.notNull(entity.getGoodsImageUrl(), "{}({})不能为空", "商品图片URL","goodsImageUrl");
Assert.notNull(entity.getRequiredPoints(), "{}({})不能为空", "所需积分", "requiredPoints");
Assert.notNull(entity.getExtraPrice(), "{}({})不能为空", "额外价格", "extraPrice");
Assert.notNull(entity.getSort(), "{}({})不能为空", "排序(权重)", "sort");
Assert.notNull(entity.getQuantity(), "{}({})不能为空", "数量", "quantity");
//Assert.notEmpty(entity.getGoodsDescription(), "{}({})不能为空", "商品详情","goodsDescription");
Assert.notNull(entity.getStatus(), "{}({})不能为空", "是否上架", "status");
} catch (IllegalArgumentException e) {
throw new MsgException(e.getMessage());
}
entity.setCreateTime(new Date());
return super.save(entity);
}
@Override
public boolean update(TbPointsGoodsSetting dto) {
try {
Assert.notNull(dto.getId(), "{}不能为空", "商品id");
Assert.notNull(dto.getShopId(), "{}({})不能为空", "店铺id", "shopId");
Assert.notEmpty(dto.getGoodsCategory(), "{}({})不能为空", "商品类型", "goodsCategory");
Assert.notEmpty(dto.getGoodsName(), "{}({})不能为空", "商品名称", "goodsName");
//Assert.notNull(entity.getGoodsImageUrl(), "{}({})不能为空", "商品图片URL","goodsImageUrl");
Assert.notNull(dto.getRequiredPoints(), "{}({})不能为空", "所需积分", "requiredPoints");
Assert.notNull(dto.getExtraPrice(), "{}({})不能为空", "额外价格", "extraPrice");
Assert.notNull(dto.getSort(), "{}({})不能为空", "排序(权重)", "sort");
Assert.notNull(dto.getQuantity(), "{}({})不能为空", "数量", "quantity");
//Assert.notEmpty(entity.getGoodsDescription(), "{}({})不能为空", "商品详情","goodsDescription");
Assert.notNull(dto.getStatus(), "{}({})不能为空", "是否上架", "status");
} catch (IllegalArgumentException e) {
throw new MsgException(e.getMessage());
}
TbPointsGoodsSetting entity = super.getById(dto.getId());
BeanUtil.copyProperties(dto, entity, CopyOptions.create().setIgnoreNullValue(false).setIgnoreProperties("createTime"));
entity.setUpdateTime(new Date());
return super.updateById(entity);
}
}