This commit is contained in:
磷叶 2025-01-18 10:36:47 +08:00
parent 9afb61f2ea
commit 3bdd6f3591
15 changed files with 218 additions and 14 deletions

View File

@ -22,7 +22,8 @@ public enum PayBillBstType {
MONTH_BILL("1", "月费账单", null, null),
ELECTRICITY_RECHARGE("2", "电量充值订单", null, null),
RECHARGE_ORDER("4", "充值订单", RechargePayHandler.class, RechargePayHandler.class),
RECHARGE_ORDER_DEPOSIT("5", "充值订单押金", RechargeDepositAfterPay.class, null);
RECHARGE_ORDER_DEPOSIT("5", "充值订单押金", RechargeDepositAfterPay.class, null),
VIP_ORDER("6", "VIP订单", null, null);
private final String type;
private final String msg;

View File

@ -3,6 +3,7 @@ package com.ruoyi.ss.payBill.service;
import com.ruoyi.ss.payBill.domain.PayBill;
import com.ruoyi.ss.transactionBill.domain.bo.RechargePayDepositBO;
import com.ruoyi.ss.transactionBill.domain.dto.RechargePayBO;
import com.ruoyi.ss.vipOrder.domain.bo.AddPayVipOrderBO;
/**
* @author wjh
@ -19,4 +20,9 @@ public interface PayBillConverter {
* 充值订单押金支付转为支付订单
*/
PayBill toPoByRechargeDeposit(RechargePayDepositBO bo);
/**
* VIP订单BO 转为支付订单
*/
PayBill toPoByVipOrderBO(AddPayVipOrderBO bo);
}

View File

@ -5,6 +5,7 @@ import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.domain.enums.ChannelPlatform;
import com.ruoyi.ss.channel.service.ChannelService;
import com.ruoyi.ss.payBill.domain.PayBill;
import com.ruoyi.ss.payBill.domain.PayBillVO;
import com.ruoyi.ss.payBill.domain.enums.PayBillBstType;
import com.ruoyi.ss.payBill.domain.enums.PayBillStatus;
import com.ruoyi.ss.payBill.service.PayBillConverter;
@ -13,6 +14,8 @@ import com.ruoyi.ss.transactionBill.domain.dto.RechargePayBO;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.user.domain.SmUserVO;
import com.ruoyi.ss.user.service.UserService;
import com.ruoyi.ss.vipOrder.domain.VipOrder;
import com.ruoyi.ss.vipOrder.domain.bo.AddPayVipOrderBO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -124,4 +127,40 @@ public class PayBillConverterImpl implements PayBillConverter {
return po;
}
@Override
public PayBill toPoByVipOrderBO(AddPayVipOrderBO bo) {
if (bo == null) {
return null;
}
VipOrder order = bo.getOrder();
SmUserVO user = bo.getUser();
ChannelVO channel = bo.getChannel();
if (order == null || channel == null || user == null) {
return null;
}
PayBill pay = new PayBillVO();
pay.setBstType(PayBillBstType.VIP_ORDER.getType());
// 订单数据
pay.setBstId(order.getId());
pay.setAmount(order.getAmount());
pay.setDescription("VIP订单:" + order.getOrderNo());
// 渠道数据
pay.setChannelId(channel.getChannelId());
pay.setChannelCost(this.calcChannelCost(channel, order.getAmount()));
// 用户数据
pay.setAppId(user.getAppId());
if (ChannelPlatform.WX.getCode().equals(channel.getPlatform())) {
pay.setAccount(user.getWxOpenId());
} else if (ChannelPlatform.ALI.getCode().equals(channel.getPlatform())) {
pay.setAccount(user.getAliOpenId());
}
// 基础数据
pay.setIp(IpUtils.getIpAddr());
pay.setStatus(PayBillStatus.WAIT_PAY.getStatus());
return pay;
}
}

View File

@ -1,6 +1,5 @@
package com.ruoyi.ss.user.domain;
import com.ruoyi.common.core.domain.entity.SmUser;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@ -13,7 +12,7 @@ import java.util.List;
* 2024/3/7
*/
@Data
public class SmUserQuery extends SmUser {
public class SmUserQuery extends SmUserVO {
@ApiModelProperty("用户id列表")
private List<Long> userIds;

View File

@ -95,6 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="showBillMobile != null "> and show_bill_mobile = #{showBillMobile}</if>
<if test="excludeUserId != null">and su.user_id != #{excludeUserId}</if>
<if test="aliOpenId != null and aliOpenId != ''">and su.ali_open_id like concat('%', #{aliOpenId}, '%')</if>
<if test="appName != null and appName != ''">and sa.name like concat('%', #{appName}, '%')</if>
<if test="eqAliOpenId != null and eqAliOpenId != ''">and su.ali_open_id = #{eqAliOpenId}</if>
<if test="agentAllowMchSwitch != null">and su.agent_allow_mch_switch != #{agentAllowMchSwitch}</if>
<if test="realOrUserName != null and realOrUserName != ''">and if(su.is_real, su.real_name, su.user_name) like concat('%', #{realOrUserName}, '%')</if>

View File

@ -8,6 +8,7 @@ import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* 会员订单对象 ss_vip_order
@ -48,7 +49,11 @@ public class VipOrder extends BaseEntity
@Excel(name = "下单时的可用店铺列表")
@ApiModelProperty("下单时的可用店铺列表")
private String levelStoreIds;
private List<Long> levelStoreIds;
@Excel(name = "订单等级续费解决方案")
@ApiModelProperty("订单等级续费解决方案")
private String levelSolution;
@Excel(name = "sku ID")
@ApiModelProperty("sku ID")

View File

@ -16,6 +16,15 @@ public class VipOrderVO extends VipOrder{
@ApiModelProperty("支付渠道名称")
private String channelName;
@ApiModelProperty("用户名称")
private String userName;
@ApiModelProperty("商户名称")
private String mchName;
@ApiModelProperty("支付订单编号")
private String payNo;
@ApiModelProperty("支付时间")
private LocalDateTime payTime;
}

View File

@ -4,6 +4,7 @@ import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.user.domain.SmUserVO;
import com.ruoyi.ss.vipLevel.domain.VipLevelVO;
import com.ruoyi.ss.vipLevelSku.domain.VipLevelSkuVO;
import com.ruoyi.ss.vipOrder.domain.VipOrder;
import com.ruoyi.ss.vipOrder.domain.dto.AddPayVipOrderDTO;
import lombok.Data;
@ -32,4 +33,7 @@ public class AddPayVipOrderBO {
// 商户
private SmUserVO mch;
// 订单数据
private VipOrder order;
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.ss.vipOrder.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author wjh
* 2025/1/18
*/
@Getter
@AllArgsConstructor
public enum VipOrderStatus {
WAIT_PAY("1", "待支付"),
SUCCESS("2", "支付成功"),
CANCEL("3", "已取消");
private final String status;
private final String msg;
}

View File

@ -1,5 +1,7 @@
package com.ruoyi.ss.vipOrder.domain.vo;
import com.ruoyi.ss.vipOrder.domain.VipOrder;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
@ -8,4 +10,11 @@ import lombok.Data;
*/
@Data
public class AddAndPayVO {
@ApiModelProperty("订单数据")
private VipOrder order;
@ApiModelProperty("支付参数")
private Object payParams;
}

View File

@ -4,7 +4,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.ss.vipOrder.mapper.VipOrderMapper">
<resultMap type="VipOrderVO" id="VipOrderResult" autoMapping="true"/>
<resultMap type="VipOrderVO" id="VipOrderResult" autoMapping="true">
<result property="levelStoreIds" column="level_store_ids" typeHandler="com.ruoyi.system.mapper.typehandler.LongSplitListTypeHandler"/>
</resultMap>
<sql id="selectVipOrderVo">
select
@ -16,6 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
svo.level_name,
svo.level_discount,
svo.level_store_ids,
svo.level_solution,
svo.sku_id,
svo.sku_time,
svo.sku_price,
@ -46,6 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.payId != null"> and svo.pay_id = #{query.payId}</if>
<if test="query.status != null and query.status != ''"> and svo.status = #{query.status}</if>
<if test="query.cancelReason != null and query.cancelReason != ''"> and svo.cancel_reason like concat('%', #{query.cancelReason}, '%')</if>
<if test="query.levelSolution != null and query.levelSolution != ''"> and svo.level_solution = #{query.levelSolution}</if>
${query.params.dataScope}
</sql>
@ -71,6 +75,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="levelName != null and levelName != ''">level_name,</if>
<if test="levelDiscount != null">level_discount,</if>
<if test="levelStoreIds != null and levelStoreIds != ''">level_store_ids,</if>
<if test="levelSolution != null and levelSolution != ''">level_solution,</if>
<if test="skuId != null">sku_id,</if>
<if test="skuTime != null">sku_time,</if>
<if test="skuPrice != null">sku_price,</if>
@ -91,7 +96,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="levelId != null">#{levelId},</if>
<if test="levelName != null and levelName != ''">#{levelName},</if>
<if test="levelDiscount != null">#{levelDiscount},</if>
<if test="levelStoreIds != null and levelStoreIds != ''">#{levelStoreIds},</if>
<if test="levelStoreIds != null and levelStoreIds != ''">#{levelStoreIds,typeHandler=com.ruoyi.system.mapper.typehandler.LongSplitListTypeHandler},</if>
<if test="levelSolution != null and levelSolution != ''">#{levelSolution},</if>
<if test="skuId != null">#{skuId},</if>
<if test="skuTime != null">#{skuTime},</if>
<if test="skuPrice != null">#{skuPrice},</if>
@ -122,7 +128,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.levelId != null">level_id = #{data.levelId},</if>
<if test="data.levelName != null and data.levelName != ''">level_name = #{data.levelName},</if>
<if test="data.levelDiscount != null">level_discount = #{data.levelDiscount},</if>
<if test="data.levelStoreIds != null and data.levelStoreIds != ''">level_store_ids = #{data.levelStoreIds},</if>
<if test="data.levelStoreIds != null and data.levelStoreIds != ''">level_store_ids = #{data.levelStoreIds,typeHandler=com.ruoyi.system.mapper.typehandler.LongSplitListTypeHandler},</if>
<if test="data.levelSolution != null and data.levelSolution != ''">level_solution = #{data.levelSolution},</if>
<if test="data.skuId != null">sku_id = #{data.skuId},</if>
<if test="data.skuTime != null">sku_time = #{data.skuTime},</if>
<if test="data.skuPrice != null">sku_price = #{data.skuPrice},</if>

View File

@ -1,5 +1,6 @@
package com.ruoyi.ss.vipOrder.service;
import com.ruoyi.ss.vipOrder.domain.VipOrder;
import com.ruoyi.ss.vipOrder.domain.bo.AddPayVipOrderBO;
import com.ruoyi.ss.vipOrder.domain.dto.AddPayVipOrderDTO;
@ -14,4 +15,8 @@ public interface VipOrderConverter {
*/
AddPayVipOrderBO toBO(AddPayVipOrderDTO dto);
/**
* BO转为订单数据
*/
VipOrder toOrder(AddPayVipOrderBO bo);
}

View File

@ -2,17 +2,24 @@ package com.ruoyi.ss.vipOrder.service.impl;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.ss.channel.service.ChannelService;
import com.ruoyi.ss.user.domain.SmUserVO;
import com.ruoyi.ss.user.service.UserService;
import com.ruoyi.ss.vipLevel.domain.VipLevelVO;
import com.ruoyi.ss.vipLevel.service.VipLevelService;
import com.ruoyi.ss.vipLevelSku.domain.VipLevelSkuVO;
import com.ruoyi.ss.vipLevelSku.service.VipLevelSkuService;
import com.ruoyi.ss.vipOrder.domain.VipOrder;
import com.ruoyi.ss.vipOrder.domain.VipOrderQuery;
import com.ruoyi.ss.vipOrder.domain.bo.AddPayVipOrderBO;
import com.ruoyi.ss.vipOrder.domain.dto.AddPayVipOrderDTO;
import com.ruoyi.ss.vipOrder.domain.enums.VipOrderStatus;
import com.ruoyi.ss.vipOrder.service.VipOrderConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* @author wjh
* 2025/1/17
@ -62,4 +69,52 @@ public class VipOrderConverterImpl implements VipOrderConverter {
return bo;
}
@Override
public VipOrder toOrder(AddPayVipOrderBO bo) {
if (bo == null) {
return null;
}
VipOrder order = new VipOrderQuery();
// 用户数据
SmUserVO user = bo.getUser();
if (user != null) {
order.setUserId(user.getUserId());
}
// 商户数据
SmUserVO mch = bo.getMch();
if (mch != null) {
order.setMchId(mch.getUserId());
}
// 等级数据
VipLevelVO level = bo.getLevel();
if (level != null) {
order.setLevelId(level.getId());
order.setLevelName(level.getName());
order.setLevelDiscount(level.getDiscount());
order.setLevelStoreIds(level.getStoreIds());
}
// 解决方案
AddPayVipOrderDTO dto = bo.getDto();
if (dto != null) {
order.setLevelSolution(dto.getSolution());
}
// sku数据
VipLevelSkuVO sku = bo.getSku();
if (sku != null) {
order.setSkuId(sku.getId());
order.setSkuTime(sku.getTime());
order.setSkuPrice(sku.getPrice());
order.setSkuLimitType(sku.getLimitType());
order.setSkuLimitCount(sku.getLimitCount());
}
// 基础数据
BigDecimal amount = sku == null || sku.getPrice() == null ? BigDecimal.ZERO : sku.getPrice();
order.setAmount(amount);
order.setExpireTime(LocalDateTime.now().plusMinutes(15)); // 15分钟内过期
order.setStatus(VipOrderStatus.WAIT_PAY.getStatus());
return order;
}
}

View File

@ -1,16 +1,24 @@
package com.ruoyi.ss.vipOrder.service.impl;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.SnowFlakeUtil;
import com.ruoyi.ss.payBill.domain.PayBill;
import com.ruoyi.ss.payBill.domain.vo.DoPayVO;
import com.ruoyi.ss.payBill.service.PayBillConverter;
import com.ruoyi.ss.payBill.service.PayBillService;
import com.ruoyi.ss.vipOrder.domain.VipOrder;
import com.ruoyi.ss.vipOrder.domain.VipOrderQuery;
import com.ruoyi.ss.vipOrder.domain.VipOrderVO;
import com.ruoyi.ss.vipOrder.domain.bo.AddPayVipOrderBO;
import com.ruoyi.ss.vipOrder.domain.vo.AddAndPayVO;
import com.ruoyi.ss.vipOrder.mapper.VipOrderMapper;
import com.ruoyi.ss.vipOrder.service.VipOrderConverter;
import com.ruoyi.ss.vipOrder.service.VipOrderService;
import com.ruoyi.ss.vipOrder.service.VipOrderValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.List;
@ -29,6 +37,18 @@ public class VipOrderServiceImpl implements VipOrderService
@Autowired
private VipOrderValidator vipOrderValidator;
@Autowired
private VipOrderConverter vipOrderConverter;
@Autowired
private PayBillConverter payBillConverter;
@Autowired
private PayBillService payBillService;
@Autowired
private TransactionTemplate transactionTemplate;
/**
* 查询会员订单
*
@ -63,6 +83,7 @@ public class VipOrderServiceImpl implements VipOrderService
public int insertVipOrder(VipOrder vipOrder)
{
vipOrder.setCreateTime(DateUtils.getNowDate());
vipOrder.setOrderNo(String.valueOf(SnowFlakeUtil.newId()));
return vipOrderMapper.insertVipOrder(vipOrder);
}
@ -107,14 +128,32 @@ public class VipOrderServiceImpl implements VipOrderService
// 校验
vipOrderValidator.preAddAndPay(bo);
AddAndPayVO vo = new AddAndPayVO();
// 结果
AddAndPayVO result = new AddAndPayVO();
// 创建订单
// 转为订单数据
VipOrder order = vipOrderConverter.toOrder(bo);
ServiceUtil.assertion(order == null, "订单数据为空");
// 订单数据加入结果集和上下文
result.setOrder(order);
bo.setOrder(order);
// 创建支付单
// 操作数据库
transactionTemplate.execute(status -> {
// 创建订单
int insert = this.insertVipOrder(order);
ServiceUtil.assertion(insert != 1, "创建订单失败");
// 调起支付
// 创建并支付
PayBill pay = payBillConverter.toPoByVipOrderBO(bo);
ServiceUtil.assertion(pay == null, "支付单数据为空");
DoPayVO payResult = payBillService.createPayBill(pay);
ServiceUtil.assertion(payResult == null, "调起支付失败");
result.setPayParams(payResult.getPayParams());
return vo;
return insert;
});
return result;
}
}

View File

@ -14,6 +14,7 @@ import com.ruoyi.ss.vipLevelSku.domain.enums.VipLevelSkuStatus;
import com.ruoyi.ss.vipOrder.domain.bo.AddPayVipOrderBO;
import com.ruoyi.ss.vipOrder.domain.dto.AddPayVipOrderDTO;
import com.ruoyi.ss.vipOrder.service.VipOrderValidator;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -47,7 +48,8 @@ public class VipOrderValidatorImpl implements VipOrderValidator {
ServiceUtil.assertion(!VipLevelSkuStatus.ON_SALE.getStatus().equals(sku.getStatus()), "ID为%s的SKU目前不可购买", sku.getId());
ServiceUtil.assertion(!Objects.equals(dto.getSkuLimitType(), sku.getLimitType()), "当前使用限制已发生变化,请重新下单");
ServiceUtil.assertion(!Objects.equals(dto.getSkuLimitCount(), sku.getLimitCount()), "当前限制次数已发生变化,请重新下单");
ServiceUtil.assertion(!Objects.equals(dto.getSkuPrice(), sku.getPrice()), "当前价格已发生变化,请重新下单");
ServiceUtil.assertion(sku.getPrice() == null, "价格不允许为空,请重新下单");
ServiceUtil.assertion(!MathUtils.equals(dto.getSkuPrice(), sku.getPrice()), "当前价格已发生变化,请重新下单");
ServiceUtil.assertion(!Objects.equals(dto.getSkuTime(), sku.getTime()), "当前可购买的时长已发生变化,请重新下单");
ServiceUtil.assertion(!MathUtils.equals(dto.getLevelDiscount(), level.getDiscount()), "当前折扣已发生变化,请重新下单");
ServiceUtil.assertion(!CollectionUtils.equals(dto.getLevelStoreIds(), level.getStoreIds()), "当前可用店铺已发生变化,请重新下单");
@ -62,7 +64,9 @@ public class VipOrderValidatorImpl implements VipOrderValidator {
ServiceUtil.assertion(channel.getEnabled() == null || !channel.getEnabled(), "ID为%s的支付渠道已禁用", channel.getChannelId());
// 校验用户VIP兼容性若不兼容则校验是否有选择方案
this.isCompatibility(sku, level, user);
if (this.isCompatibility(sku, level, user)) {
ServiceUtil.assertion(StringUtils.isBlank(dto.getSolution()), "当前拥有的VIP与下单的VIP不兼容请选择解决方案");
}
}
/**