Compare commits

...

2 Commits

Author SHA1 Message Date
7dcb1ef9a9 Merge pull request '会员支付优化(现金支付)' (#93) from khy1 into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #93
2024-10-29 18:34:46 +08:00
khy
566cf302c4 会员支付优化(现金支付) 2024-10-29 18:29:55 +08:00
13 changed files with 440 additions and 129 deletions

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.trade.dal.dataobject.type;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
/**
* 会员卡类型 DO
*
* @author 芋道源码
*/
@TableName("paid_member_card_type")
@KeySequence("paid_member_card_type_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TradePaidMemberCardTypeDO extends TenantBaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 会员名
*/
private String name;
/**
* 有效期
*/
private String vid;
/**
* 原价
*/
private BigDecimal originalPrice;
/**
* 优惠价
*/
private BigDecimal specialPrice;
/**
* 排序
*/
private String sort;
/**
* 是否禁用
*/
private Boolean status;
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.trade.dal.mysql.type;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.dal.dataobject.type.TradePaidMemberCardTypeDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 会员卡类型 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface TradePaidMemberCardTypeMapper extends BaseMapperX<TradePaidMemberCardTypeDO> {
default List<TradePaidMemberCardTypeDO> selectListByStatus(Integer status){
return selectList(TradePaidMemberCardTypeDO::getStatus, status);
}
default List<TradePaidMemberCardTypeDO> selectListByIsActivate(Integer status){
return selectList(new LambdaQueryWrapperX<TradePaidMemberCardTypeDO>()
.eqIfPresent(TradePaidMemberCardTypeDO::getStatus,status)
.neIfPresent(TradePaidMemberCardTypeDO::getName,"试用")
.orderByAsc(TradePaidMemberCardTypeDO::getId));
}
}

View File

@ -14,7 +14,7 @@ public interface TradePaidMemberUserService {
LocalDateTime getDeadLineDay(String cardName);
LocalDateTime getDeadLineDay(String cardName,Long userId);
TradePaidMemberUserDO getPaidMemberUserByOrderNo(String orderNO);
@ -34,4 +34,8 @@ public interface TradePaidMemberUserService {
TradePaidMemberUserDO getByPayOrderId(Long payOrderId);
/*
* 现金支付后更新会员记录状态
* */
void updateStatus(TradePaidMemberUserDO tradePaidMemberUserDO,String channelCode);
}

View File

@ -0,0 +1,151 @@
package cn.iocoder.yudao.module.trade.service.member;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.dal.dataobject.member.TradeMemberUserDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.member.TradePaidMemberUserDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.type.TradePaidMemberCardTypeDO;
import cn.iocoder.yudao.module.trade.dal.mysql.member.TradePaidMemberUserMapper;
import cn.iocoder.yudao.module.trade.service.type.TradePaidMemberCardTypeService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.PAID_MEMBER_ORDER_NOT_EXISTS;
/**
* 会员 Service 实现类
*
* @author 管理员
*/
@Service
@Validated
public class TradePaidMemberUserServiceImpl implements TradePaidMemberUserService {
@Resource
private TradePaidMemberUserMapper tradePaidMemberUserMapper;
@Resource
private TradeMemberUserService tradeMemberUserService;
@Resource
private TradePaidMemberCardTypeService tradePaidMemberCardTypeService;
private void validateMemberUserExists(Long id) {
if (tradePaidMemberUserMapper.selectById(id) == null) {
throw exception(PAID_MEMBER_ORDER_NOT_EXISTS);
}
}
//获取会员类型对应的过期时间
@Override
public LocalDateTime getDeadLineDay(String cardName,Long userId) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime deadlineDay;
TradeMemberUserDO tradeMemberUserDO = tradeMemberUserService.getUser(userId);
//判断是否为会员是否需要续期
if(tradeMemberUserDO.getActivate() !=1
&& tradeMemberUserDO.getActivate() != 2
&& tradeMemberUserDO.getActivate() != 3){
deadlineDay = getDay(cardName,now);
}
else {
List<TradePaidMemberUserDO> list = tradePaidMemberUserMapper.selectList(new LambdaQueryWrapperX<TradePaidMemberUserDO>()
.eqIfPresent(TradePaidMemberUserDO::getUid, userId)
.isNotNull(TradePaidMemberUserDO::getCardExpirationTime)
.orderByDesc(TradePaidMemberUserDO::getId));
now = CollUtil.getFirst(list).getCardExpirationTime();
deadlineDay = getDay(cardName,now);
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY);
String dayStr = deadlineDay.format(formatter);
LocalDate expireDate = LocalDate.parse(dayStr,formatter);
deadlineDay = expireDate.atStartOfDay();
return deadlineDay;
}
public LocalDateTime getDay(String cardName,LocalDateTime dateTime) {
LocalDateTime deadlineDay;
TradePaidMemberCardTypeDO paidMemberCardTypeDO = tradePaidMemberCardTypeService.selectByName(cardName);
if (cardName.equals("试用")){
deadlineDay = dateTime.plus(Long.parseLong(paidMemberCardTypeDO.getVid()), ChronoUnit.DAYS);
} else if (cardName.equals("月卡")) {
deadlineDay = dateTime.plus(1,ChronoUnit.MONTHS);
} else if (cardName.equals("季卡")) {
deadlineDay = dateTime.plus(3,ChronoUnit.MONTHS);
} else if (cardName.equals("年卡")) {
deadlineDay = dateTime.plus(1,ChronoUnit.YEARS);
} else {
//永久设置为一个非常远的的日期
deadlineDay = LocalDateTime.of(9999,12,31,23,59,59);
}
return deadlineDay;
}
@Override
public TradePaidMemberUserDO getPaidMemberUserByOrderNo(String orderNO) {
TradePaidMemberUserDO tradePaidMemberUserDO = tradePaidMemberUserMapper.selectOne(TradePaidMemberUserDO::getOrderNo,orderNO);
return tradePaidMemberUserDO;
}
@Override
public String currentPayType(String payChannel) {
String payType = null;
if (payChannel.equals("wallet")){
payType = "余额";
} else if(payChannel.startsWith("wx")){
payType = "微信";
} else if (payChannel.startsWith("alipay")) {
payType = "支付宝";
} else {
payType = "模拟支付";
}
return payType;
}
@Override
public void update(TradePaidMemberUserDO updateReqVO) {
// 校验存在
validateMemberUserExists(updateReqVO.getId());
tradePaidMemberUserMapper.updateById(updateReqVO);
}
@Override
public TradePaidMemberUserDO getByPayOrderId(Long payOrderId) {
TradePaidMemberUserDO tradePaidMemberUserDO = tradePaidMemberUserMapper.selectOne(
new LambdaQueryWrapperX<TradePaidMemberUserDO>().eqIfPresent(TradePaidMemberUserDO::getPayOrderId,payOrderId));
return tradePaidMemberUserDO;
}
@Override
public void updateStatus(TradePaidMemberUserDO tradePaidMemberUserDO,String channelCode) {
tradePaidMemberUserDO.setPayTime(LocalDateTime.now());
tradePaidMemberUserDO.setPaid(true);
//过期时间
LocalDateTime cardExpirationTime = getDeadLineDay(tradePaidMemberUserDO.getPayMemberType(),tradePaidMemberUserDO.getUid());
tradePaidMemberUserDO.setCardExpirationTime(cardExpirationTime);
tradePaidMemberUserDO.setPayChannel(channelCode);
//支付方式
String payType = currentPayType(channelCode);
tradePaidMemberUserDO.setPayType(payType);
//更新会员订单
update(tradePaidMemberUserDO);
System.out.println("成功更新会员订单paid"+tradePaidMemberUserDO);
//更新用户会员状态
tradeMemberUserService.updateActivate(tradePaidMemberUserDO.getPayMemberType(),tradePaidMemberUserDO.getUid());
}
}

View File

@ -1,94 +0,0 @@
package cn.iocoder.yudao.module.trade.service.member;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.dal.dataobject.member.TradePaidMemberUserDO;
import cn.iocoder.yudao.module.trade.dal.mysql.member.TradePaidMemberUserMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.PAID_MEMBER_ORDER_NOT_EXISTS;
/**
* 会员 Service 实现类
*
* @author 管理员
*/
@Service
@Validated
public class TradeTradePaidMemberUserServiceImpl implements TradePaidMemberUserService {
@Resource
private TradePaidMemberUserMapper tradePaidMemberUserMapper;
private void validateMemberUserExists(Long id) {
if (tradePaidMemberUserMapper.selectById(id) == null) {
throw exception(PAID_MEMBER_ORDER_NOT_EXISTS);
}
}
//获取会员类型对应的过期时间
@Override
public LocalDateTime getDeadLineDay(String cardName) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime deadlineDay;
//判断是否具有过期时间该操作为续费
if (cardName.equals("试用")){
deadlineDay = now.plus(1, ChronoUnit.DAYS);
} else if (cardName.equals("月卡")) {
deadlineDay = now.plus(1,ChronoUnit.MONTHS);
} else if (cardName.equals("季卡")) {
deadlineDay = now.plus(3,ChronoUnit.MONTHS);
} else if (cardName.equals("年卡")) {
deadlineDay = now.plus(1,ChronoUnit.YEARS);
} else {
//永久设置为一个非常远的的日期
deadlineDay = LocalDateTime.of(9999,12,31,23,59,59);
}
return deadlineDay;
}
@Override
public TradePaidMemberUserDO getPaidMemberUserByOrderNo(String orderNO) {
TradePaidMemberUserDO tradePaidMemberUserDO = tradePaidMemberUserMapper.selectOne(TradePaidMemberUserDO::getOrderNo,orderNO);
return tradePaidMemberUserDO;
}
@Override
public String currentPayType(String payChannel) {
String payType = null;
if (payChannel.equals("wallet")){
payType = "余额";
} else if(payChannel.startsWith("wx")){
payType = "微信";
} else if (payChannel.startsWith("alipay")) {
payType = "支付宝";
} else {
payType = "模拟支付";
}
return payType;
}
@Override
public void update(TradePaidMemberUserDO updateReqVO) {
// 校验存在
validateMemberUserExists(updateReqVO.getId());
tradePaidMemberUserMapper.updateById(updateReqVO);
}
@Override
public TradePaidMemberUserDO getByPayOrderId(Long payOrderId) {
TradePaidMemberUserDO tradePaidMemberUserDO = tradePaidMemberUserMapper.selectOne(
new LambdaQueryWrapperX<TradePaidMemberUserDO>().eqIfPresent(TradePaidMemberUserDO::getPayOrderId,payOrderId));
return tradePaidMemberUserDO;
}
}

View File

@ -337,24 +337,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
PayOrderRespDTO payOrder = orderResult.getValue();
System.out.println("交易订单成功id"+id+"和payOrderId"+payOrderId);
//会员用户信息支付状态修改
TradeMemberUserDO tradeMemberUserDO = tradeMemberUserService.getUser(order.getUserId());
TradePaidMemberUserDO tradePaidMemberUserDO = tradePaidMemberUserService.getByPayOrderId(payOrderId);
if(tradePaidMemberUserDO != null ){
System.out.println("进入会员支付修改操作paid"+tradePaidMemberUserDO+"和member"+tradeMemberUserDO);
tradePaidMemberUserDO.setPayTime(LocalDateTime.now());
tradePaidMemberUserDO.setPaid(true);
//过期时间
LocalDateTime cardExpirationTime = tradePaidMemberUserService.getDeadLineDay(tradePaidMemberUserDO.getPayMemberType());
tradePaidMemberUserDO.setCardExpirationTime(cardExpirationTime);
tradePaidMemberUserDO.setPayChannel(payOrder.getChannelCode());
//支付方式
String payType = tradePaidMemberUserService.currentPayType(payOrder.getChannelCode());
tradePaidMemberUserDO.setPayType(payType);
//更新会员订单
tradePaidMemberUserService.update(tradePaidMemberUserDO);
System.out.println("成功更新会员订单paid"+tradePaidMemberUserDO);
//更新用户会员状态
tradeMemberUserService.updateActivate(tradePaidMemberUserDO.getPayMemberType(),order.getUserId());
System.out.println("进入会员支付修改操作paid"+tradePaidMemberUserDO);
//更新会员状态
tradePaidMemberUserService.updateStatus(tradePaidMemberUserDO,order.getPayChannelCode());
//查询最新的用户信息
TradeMemberUserDO tradeMemberUserDO = tradeMemberUserService.getUser(order.getUserId());
System.out.println("成功更新用户的会员状态member"+ tradeMemberUserDO);
}
System.out.println("会员修改操作结束!!!");

View File

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.trade.service.type;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.trade.dal.dataobject.type.TradePaidMemberCardTypeDO;
import javax.validation.Valid;
import java.util.List;
/**
* 会员卡类型 Service 接口
*
* @author 芋道源码
*/
public interface TradePaidMemberCardTypeService {
/**
* 删除会员卡类型
*
* @param id 编号
*/
void deletecard(Long id);
/**
* 获得会员卡类型
*
* @param id 编号
* @return 会员卡类型
*/
TradePaidMemberCardTypeDO getcard(Long id);
/**
* 根据用户是否使用试用会员
* 查询会员类型列表
* @param activate
* @return
*/
List<TradePaidMemberCardTypeDO> getCardTypeList (Integer activate);
/**
* 根据会员卡名查询
*/
TradePaidMemberCardTypeDO selectByName(String cardName);
}

View File

@ -0,0 +1,78 @@
package cn.iocoder.yudao.module.trade.service.type;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.trade.dal.dataobject.type.TradePaidMemberCardTypeDO;
import cn.iocoder.yudao.module.trade.dal.mysql.type.TradePaidMemberCardTypeMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.CARD_NOT_EXISTS;
/**
* 会员卡类型 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class TradePaidMemberCardTypeServiceImpl implements TradePaidMemberCardTypeService {
@Resource
private TradePaidMemberCardTypeMapper cardMapper;
@Override
public void deletecard(Long id) {
// 校验存在
validatecardExists(id);
// 删除
cardMapper.deleteById(id);
}
private void validatecardExists(Long id) {
if (cardMapper.selectById(id) == null) {
throw exception(CARD_NOT_EXISTS);
}
}
@Override
public TradePaidMemberCardTypeDO getcard(Long id) {
return cardMapper.selectById(id);
}
@Override
public List<TradePaidMemberCardTypeDO> getCardTypeList(Integer activate) {
List<TradePaidMemberCardTypeDO> list = new ArrayList<>();
Integer status = 1;
if(activate == 0){
list = cardMapper.selectListByStatus(status);
}
else {
list = cardMapper.selectListByIsActivate(status);
}
return list;
}
@Override
public TradePaidMemberCardTypeDO selectByName(String cardName) {
TradePaidMemberCardTypeDO paidMemberCardTypeDO = cardMapper.selectOne(new LambdaQueryWrapperX<TradePaidMemberCardTypeDO>()
.eqIfPresent(TradePaidMemberCardTypeDO::getName,cardName));
validatecardExists(paidMemberCardTypeDO.getId());
return paidMemberCardTypeDO;
}
}

View File

@ -143,7 +143,7 @@ public class MemberUserDO extends TenantBaseDO {
private Long groupId;
/**
* 是否绑过卡,是否开通过会员(0未开通,1试用,2有效期,3永久)
* 是否绑过卡,是否开通过会员(0未开通,1试用,2有效期,3永久,4过期)
*/
private Integer activate;

View File

@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.member.dal.dataobject.user.PaidMemberUserDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.*;
import org.apache.ibatis.annotations.Select;
/**
* 会员 Mapper
@ -25,4 +26,15 @@ public interface PaidMemberUserMapper extends BaseMapperX<PaidMemberUserDO> {
.likeIfPresent(PaidMemberUserDO::getNickname,reqVO.getNickname())
.orderByDesc(PaidMemberUserDO::getId));
}
@Select("SELECT * FROM paid_member_user pmu " +
"INNER JOIN (" +
" SELECT uid, MAX(card_expiration_time) AS max_card_expiration_time " +
" FROM paid_member_user " +
" WHERE paid = TRUE " +
" GROUP BY uid" +
") latest " +
"ON pmu.uid = latest.uid AND pmu.card_expiration_time = latest.max_card_expiration_time " +
"WHERE pmu.paid = TRUE")
List<PaidMemberUserDO> selectLatestPaidMemberUsers();
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.member.job.user;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.member.service.user.PaidMemberUserService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class PaidMemberUserExpireJob implements JobHandler {
@Resource
private PaidMemberUserService paidMemberUserService;
@Override
@TenantJob
public String execute(String param) throws Exception {
int count = paidMemberUserService.expireMemberUser();
return StrUtil.format("会员过期{}个",count);
}
}

View File

@ -101,5 +101,5 @@ public interface PaidMemberUserService {
PaidMemberUserSaveReqVO createPaidMemberUserSaveReqVO(MemberUserDO memberUserDO, String cardName);
// int expireMemberUser();
int expireMemberUser();
}

View File

@ -1,16 +1,10 @@
package cn.iocoder.yudao.module.member.service.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
import cn.iocoder.yudao.module.member.dal.dataobject.membercardtype.PaidMemberCardTypeDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.service.membercardtype.PaidMemberCardTypeService;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
@ -121,7 +115,7 @@ public class PaidMemberUserServiceImpl implements PaidMemberUserService {
@Override
public int getPriceByTtype(Integer activate, String cardName) {
int price = 0;
if(activate == 0){
if(activate == 0 || activate == 4){
BigDecimal payprice = memberCardTypeService.selectByName(cardName).getOriginalPrice();
price = payprice.multiply(new BigDecimal("100")).intValue();
}
@ -137,7 +131,6 @@ public class PaidMemberUserServiceImpl implements PaidMemberUserService {
public LocalDateTime getDeadLineDay(String cardName,Long userId) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime deadlineDay;
PaidMemberCardTypeDO paidMemberCardTypeDO = memberCardTypeService.selectByName(cardName);
MemberUserDO memberUserDO = memberUserService.getUser(userId);
//判断是否为会员是否需要续期
if(memberUserDO.getActivate() !=1
@ -281,12 +274,25 @@ public class PaidMemberUserServiceImpl implements PaidMemberUserService {
return paidMemberUserSaveReqVO;
}
// @Override
// public int expireMemberUser() {
// List<PaidMemberUserDO> list = paidMemberUserMapper.selectList
// (new LambdaQueryWrapperX<PaidMemberUserDO>().le(PaidMemberUserDO::getCardExpirationTime,LocalDateTime.now())
// .)
// return 0;
// }
@Override
public int expireMemberUser() {
//1.查询当前会员记录里最新的会员记录
List<PaidMemberUserDO> list = paidMemberUserMapper.selectLatestPaidMemberUsers();
if(CollUtil.isEmpty(list)){
return 0;
}
//2.遍历执行
int count = 0;
for (PaidMemberUserDO paidMemberUserDO : list){
MemberUserDO memberUserDO = memberUserService.getUser(paidMemberUserDO.getUid());
if(paidMemberUserDO.getCardExpirationTime().isBefore(LocalDateTime.now())
&& memberUserDO.getActivate() != 4){
memberUserDO.setActivate(4);
memberUserService.updateUserDo(memberUserDO);
count++;
}
}
return count;
}
}