refactor(payment): 重构支付功能并优化token消费接口
- 修改reduceBalanceWithToken方法使用TokenConsumptionDto参数对象 - 添加通过会话ID查询用户的功能并验证用户会话有效性 - 在支付控制器中更新订单信息时保存二维码内容 - 为PaymentOrder实体添加codeUrl和qrCode字段支持 - 更新SysUserMapper添加getBySessionId查询方法 - 优化微信和支付宝支付回调日志记录 - 改进token消费参数验证逻辑 - 调整数据库映射文件以支持新增字段
This commit is contained in:
parent
770f50302e
commit
f2b8a735f2
|
|
@ -116,20 +116,8 @@ public class AccountController {
|
|||
@Operation(summary = "减少账户余额(token消费转换)", description = "减少账户余额(token消费转换)")
|
||||
@PostMapping("/reduceBalanceWithToken")
|
||||
@RequireAuth
|
||||
public CommonResult<Integer> reduceBalanceWithToken(
|
||||
@RequestBody TokenConsumptionDto tokenConsumptionDto) {
|
||||
return CommonResult.success(this.accountService.reduceBalanceWithToken(
|
||||
tokenConsumptionDto.getUserId(),
|
||||
tokenConsumptionDto.getInputToken(),
|
||||
tokenConsumptionDto.getOutputToken(),
|
||||
tokenConsumptionDto.getTotalTokens(),
|
||||
tokenConsumptionDto.getModelName(),
|
||||
tokenConsumptionDto.getQuestion(),
|
||||
tokenConsumptionDto.getTransactionNo(),
|
||||
tokenConsumptionDto.getBusinessId(),
|
||||
tokenConsumptionDto.getBusinessType(),
|
||||
tokenConsumptionDto.getRemark()
|
||||
));
|
||||
public CommonResult<Integer> reduceBalanceWithToken( @RequestBody TokenConsumptionDto tokenConsumptionDto) {
|
||||
return CommonResult.success(this.accountService.reduceBalanceWithToken(tokenConsumptionDto));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -108,6 +108,11 @@ public class PayController {
|
|||
PaymentOrder createdOrder = paymentOrderService.createPaymentOrder(order);
|
||||
// 生成支付宝支付表单
|
||||
String form = payService.createAlipay(createdOrder);
|
||||
|
||||
// 更新订单信息
|
||||
createdOrder.setQrCode( form);
|
||||
paymentOrderService.update(createdOrder);
|
||||
|
||||
return CommonResult.success(form);
|
||||
} catch (Exception e) {
|
||||
logger.error("创建支付宝支付订单失败", e);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@ public class PaymentOrder extends BaseEntity implements Serializable {
|
|||
@Schema(description ="支付渠道订单号")
|
||||
private String channelOrderNo;
|
||||
|
||||
@Schema(description ="微信二维码URL")
|
||||
private String codeUrl;
|
||||
|
||||
@Schema(description ="支付宝二维码HTML内容")
|
||||
private String qrCode;
|
||||
|
||||
@Schema(description ="商品名称")
|
||||
private String productName;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ import lombok.Data;
|
|||
@Data
|
||||
public class TokenConsumptionDto {
|
||||
|
||||
@Schema(description ="用户ID")
|
||||
@Schema(description ="用户的会话ID")
|
||||
private String sessionId;
|
||||
|
||||
@Schema(description ="用户ID" ,hidden = true)
|
||||
private Long userId;
|
||||
|
||||
@Schema(description ="输入token")
|
||||
|
|
@ -34,10 +37,10 @@ public class TokenConsumptionDto {
|
|||
@Schema(description ="交易单号")
|
||||
private String transactionNo;
|
||||
|
||||
@Schema(description ="业务ID")
|
||||
@Schema(description ="业务ID" ,hidden = true)
|
||||
private Long businessId;
|
||||
|
||||
@Schema(description ="业务类型")
|
||||
@Schema(description ="业务类型",hidden = true)
|
||||
private String businessType;
|
||||
|
||||
@Schema(description ="备注")
|
||||
|
|
|
|||
|
|
@ -99,4 +99,5 @@ public interface AccountMapper {
|
|||
* @return 影响行数
|
||||
*/
|
||||
int deleteById(Long accountId);
|
||||
|
||||
}
|
||||
|
|
@ -86,4 +86,6 @@ public interface SysUserMapper {
|
|||
|
||||
SysUser getByTel(String tel);
|
||||
|
||||
SysUser getBySessionId(String sessionId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.kexue.skills.service;
|
|||
import com.github.pagehelper.PageInfo;
|
||||
import com.kexue.skills.entity.Account;
|
||||
import com.kexue.skills.entity.dto.AccountDto;
|
||||
import com.kexue.skills.entity.dto.TokenConsumptionDto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
|
@ -104,20 +105,10 @@ public interface AccountService extends BaseService {
|
|||
|
||||
/**
|
||||
* 减少账户余额(token消费转换)
|
||||
* @param tokenConsumptionDto token消费
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param inputToken 输入token
|
||||
* @param outputToken 输出token
|
||||
* @param totalTokens 合计tokens
|
||||
* @param modelName 处理的模型名称
|
||||
* @param question 对应回答的问题或需求
|
||||
* @param transactionNo 交易单号
|
||||
* @param businessId 业务ID
|
||||
* @param businessType 业务类型
|
||||
* @param remark 备注
|
||||
* @return 影响行数
|
||||
*/
|
||||
int reduceBalanceWithToken(Long userId, Integer inputToken, Integer outputToken, Integer totalTokens, String modelName, String question, String transactionNo, Long businessId, String businessType, String remark);
|
||||
int reduceBalanceWithToken(TokenConsumptionDto tokenConsumptionDto);
|
||||
|
||||
/**
|
||||
* 增加账户余额(签到奖励token转换)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@ import com.github.pagehelper.PageHelper;
|
|||
import com.github.pagehelper.PageInfo;
|
||||
import com.kexue.skills.entity.Account;
|
||||
import com.kexue.skills.entity.AccountTransaction;
|
||||
import com.kexue.skills.entity.SysUser;
|
||||
import com.kexue.skills.entity.dto.AccountDto;
|
||||
import com.kexue.skills.common.Assert;
|
||||
import com.kexue.skills.entity.dto.TokenConsumptionDto;
|
||||
import com.kexue.skills.exception.BizException;
|
||||
import com.kexue.skills.mapper.AccountMapper;
|
||||
import com.kexue.skills.mapper.AccountTransactionMapper;
|
||||
import com.kexue.skills.mapper.SysUserMapper;
|
||||
import com.kexue.skills.service.AccountService;
|
||||
import com.kexue.skills.service.ModelPriceService;
|
||||
import com.kexue.skills.entity.ModelPrice;
|
||||
|
|
@ -31,6 +34,8 @@ import java.util.List;
|
|||
public class AccountServiceImpl implements AccountService {
|
||||
@Resource
|
||||
private AccountMapper accountMapper;
|
||||
@Resource
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
@Resource
|
||||
private AccountTransactionMapper accountTransactionMapper;
|
||||
|
|
@ -246,40 +251,35 @@ public class AccountServiceImpl implements AccountService {
|
|||
|
||||
/**
|
||||
* 减少账户余额(token消费转换)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param amount 减少金额
|
||||
* @param inputToken 输入token
|
||||
* @param outputToken 输出token
|
||||
* @param totalTokens 合计tokens
|
||||
* @param modelName 处理的模型名称
|
||||
* @param question 对应回答的问题或需求
|
||||
* @param transactionNo 交易单号
|
||||
* @param businessId 业务ID
|
||||
* @param businessType 业务类型
|
||||
* @param remark 备注
|
||||
* @return 影响行数
|
||||
*/
|
||||
@Override
|
||||
public int reduceBalanceWithToken(Long userId, Integer inputToken, Integer outputToken, Integer totalTokens, String modelName, String question, String transactionNo, Long businessId, String businessType, String remark) {
|
||||
public int reduceBalanceWithToken(TokenConsumptionDto dto) {
|
||||
validate(dto);
|
||||
// 1. 查询账户信息
|
||||
Long userId = null ;//根据会话ID查询用户ID
|
||||
SysUser bySessionId = sysUserMapper.getBySessionId(dto.getSessionId());
|
||||
if(bySessionId == null){
|
||||
throw new BizException("会话ID不存在");
|
||||
}
|
||||
userId = bySessionId.getUserId();
|
||||
Account account = this.queryByUserId(userId);
|
||||
Assert.notNull(account, "账户不存在");
|
||||
|
||||
// 2. 查询模型价格信息
|
||||
ModelPrice modelPrice = modelPriceService.queryByModelName(modelName);
|
||||
ModelPrice modelPrice = modelPriceService.queryByModelName(dto.getModelName());
|
||||
Assert.notNull(modelPrice, "模型价格信息不存在");
|
||||
|
||||
// 3. 计算金额
|
||||
// 输入token费用:输入token数量 / inputPerCent,不足1分按1分计算
|
||||
long inputFee = inputToken / modelPrice.getInputPerCent();
|
||||
if (inputToken % modelPrice.getInputPerCent() > 0) {
|
||||
long inputFee = dto.getInputToken() / modelPrice.getInputPerCent();
|
||||
if (dto.getInputToken() % modelPrice.getInputPerCent() > 0) {
|
||||
inputFee += 1;
|
||||
}
|
||||
|
||||
// 输出token费用:输出token数量 / outputPerCent,不足1分按1分计算
|
||||
long outputFee = outputToken / modelPrice.getOutputPerCent();
|
||||
if (outputToken % modelPrice.getOutputPerCent() > 0) {
|
||||
long outputFee = dto.getOutputToken() / modelPrice.getOutputPerCent();
|
||||
if (dto.getOutputToken() % modelPrice.getOutputPerCent() > 0) {
|
||||
outputFee += 1;
|
||||
}
|
||||
|
||||
|
|
@ -300,23 +300,32 @@ public class AccountServiceImpl implements AccountService {
|
|||
transaction.setBeforeBalance(account.getBalance());
|
||||
transaction.setAfterBalance(account.getBalance().subtract(amount));
|
||||
transaction.setStatus(1); // 成功
|
||||
transaction.setTransactionNo(transactionNo);
|
||||
transaction.setTransactionNo(dto.getTransactionNo());
|
||||
transaction.setPayType(3); // 余额支付
|
||||
transaction.setBusinessId(businessId);
|
||||
transaction.setBusinessType(businessType);
|
||||
transaction.setRemark(remark);
|
||||
transaction.setRemark(dto.getRemark());
|
||||
transaction.setIsExpense(1); // 支出
|
||||
transaction.setInputToken(inputToken);
|
||||
transaction.setOutputToken(outputToken);
|
||||
transaction.setTotalTokens(totalTokens);
|
||||
transaction.setModelName(modelName);
|
||||
transaction.setQuestion(question);
|
||||
transaction.setInputToken(dto.getInputToken());
|
||||
transaction.setOutputToken(dto.getOutputToken());
|
||||
transaction.setTotalTokens(dto.getTotalTokens());
|
||||
transaction.setModelName(dto.getModelName());
|
||||
transaction.setQuestion(dto.getQuestion());
|
||||
this.accountTransactionMapper.insert(transaction);
|
||||
|
||||
// 6. 更新账户余额
|
||||
return this.accountMapper.updateBalance(userId, amount, 2);
|
||||
}
|
||||
|
||||
void validate(TokenConsumptionDto dto) {
|
||||
Assert.notNull(dto, "参数不能为空");
|
||||
Assert.notNull(dto.getSessionId(), "会话ID不能为空");
|
||||
Assert.notNull(dto.getUserId(), "用户ID不能为空");
|
||||
Assert.notNull(dto.getQuestion(), "问题不能为空");
|
||||
Assert.notNull(dto.getModelName(), "模型名称不能为空");
|
||||
Assert.notNull(dto.getQuestion(), "问题不能为空");
|
||||
Assert.notNull(dto.getModelName(), "模型名称不能为空");
|
||||
Assert.notNull(dto.getQuestion(), "问题不能为空");
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加账户余额(签到奖励token转换)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -424,9 +424,15 @@ public class PayServiceImpl implements PayService {
|
|||
throw new RuntimeException("支付下单失败:" + errorMsg);
|
||||
}
|
||||
|
||||
// 保存微信支付二维码URL到订单
|
||||
String codeUrl = result.get("code_url");
|
||||
order.setCodeUrl(codeUrl);
|
||||
order.setChannelOrderNo(result.get("order_no"));
|
||||
paymentOrderService.update(order);
|
||||
|
||||
// 返回成功结果
|
||||
Map<String, String> payParams = new HashMap<>();
|
||||
payParams.put("code_url", result.get("code_url"));
|
||||
payParams.put("code_url", codeUrl);
|
||||
payParams.put("order_no", order.getOrderNo());
|
||||
return payParams;
|
||||
|
||||
|
|
@ -460,6 +466,8 @@ public class PayServiceImpl implements PayService {
|
|||
// 解析XML
|
||||
Map<String, String> params = xmlToMap(xmlData);
|
||||
|
||||
logger.info("微信支付回调数据:{}", params);
|
||||
|
||||
// 验证签名
|
||||
String sign = params.get("sign");
|
||||
if (sign == null) {
|
||||
|
|
@ -543,7 +551,11 @@ public class PayServiceImpl implements PayService {
|
|||
// 生成支付表单
|
||||
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
|
||||
if (response.isSuccess()) {
|
||||
return response.getBody();
|
||||
String htmlForm = response.getBody();
|
||||
// 保存支付宝支付HTML内容到订单
|
||||
order.setQrCode(htmlForm);
|
||||
paymentOrderService.update(order);
|
||||
return htmlForm;
|
||||
} else {
|
||||
logger.error("支付宝支付下单失败: {}", response.getMsg());
|
||||
throw new RuntimeException("支付宝支付下单失败: " + response.getMsg());
|
||||
|
|
@ -570,6 +582,8 @@ public class PayServiceImpl implements PayService {
|
|||
}
|
||||
});
|
||||
|
||||
logger.info("支付宝支付回调参数: {}", params);
|
||||
|
||||
// 初始化支付宝客户端
|
||||
AlipayClient alipayClient = new DefaultAlipayClient(
|
||||
paymentConfig.getAlipay().getGatewayUrl(),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
<result property="payType" column="pay_type" jdbcType="INTEGER"/>
|
||||
<result property="status" column="status" jdbcType="INTEGER"/>
|
||||
<result property="channelOrderNo" column="channel_order_no" jdbcType="VARCHAR"/>
|
||||
<result property="codeUrl" column="code_url" jdbcType="VARCHAR"/>
|
||||
<result property="qrCode" column="qr_code" jdbcType="LONGNVARCHAR"/>
|
||||
<result property="businessId" column="business_id" jdbcType="BIGINT"/>
|
||||
<result property="businessType" column="business_type" jdbcType="VARCHAR"/>
|
||||
<result property="remark" column="remark" jdbcType="VARCHAR"/>
|
||||
|
|
@ -25,7 +27,7 @@
|
|||
<select id="queryById" resultMap="PaymentOrderMap">
|
||||
select
|
||||
order_id, order_no, user_id, user_name, amount, pay_type, status, channel_order_no,
|
||||
business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
code_url, qr_code, business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
from payment_order
|
||||
where order_id = #{orderId}
|
||||
</select>
|
||||
|
|
@ -34,7 +36,7 @@
|
|||
<select id="queryByOrderNo" resultMap="PaymentOrderMap">
|
||||
select
|
||||
order_id, order_no, user_id, user_name, amount, pay_type, status, channel_order_no,
|
||||
business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
code_url, qr_code, business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
from payment_order
|
||||
where order_no = #{orderNo}
|
||||
</select>
|
||||
|
|
@ -43,7 +45,7 @@
|
|||
<select id="getPageList" resultMap="PaymentOrderMap">
|
||||
select
|
||||
order_id, order_no, user_id, user_name, amount, pay_type, status, channel_order_no,
|
||||
business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
code_url, qr_code, business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
from payment_order
|
||||
<where>
|
||||
<if test="userId != null">
|
||||
|
|
@ -80,7 +82,7 @@
|
|||
<select id="getList" resultMap="PaymentOrderMap">
|
||||
select
|
||||
order_id, order_no, user_id, user_name, amount, pay_type, status, channel_order_no,
|
||||
business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
code_url, qr_code, business_id, business_type, remark, create_time, update_time, create_by, update_by, delete_flag
|
||||
from payment_order
|
||||
<where>
|
||||
<if test="userId != null">
|
||||
|
|
@ -121,6 +123,8 @@
|
|||
pay_type,
|
||||
<if test="status != null">status,</if>
|
||||
<if test="channelOrderNo != null">channel_order_no,</if>
|
||||
<if test="codeUrl != null">code_url,</if>
|
||||
<if test="qrCode != null">qr_code,</if>
|
||||
<if test="businessId != null">business_id,</if>
|
||||
<if test="businessType != null">business_type,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
|
|
@ -138,6 +142,8 @@
|
|||
#{payType},
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="channelOrderNo != null">#{channelOrderNo},</if>
|
||||
<if test="codeUrl != null">#{codeUrl},</if>
|
||||
<if test="qrCode != null">#{qrCode},</if>
|
||||
<if test="businessId != null">#{businessId},</if>
|
||||
<if test="businessType != null">#{businessType},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
|
|
@ -160,6 +166,8 @@
|
|||
<if test="payType != null">pay_type = #{payType},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
<if test="channelOrderNo != null">channel_order_no = #{channelOrderNo},</if>
|
||||
<if test="codeUrl != null">code_url = #{codeUrl},</if>
|
||||
<if test="qrCode != null">qr_code = #{qrCode},</if>
|
||||
<if test="businessId != null">business_id = #{businessId},</if>
|
||||
<if test="businessType != null">business_type = #{businessType},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
|
|
|
|||
|
|
@ -208,5 +208,13 @@
|
|||
and delete_flag = 0
|
||||
limit 1
|
||||
</select>
|
||||
<select id="getBySessionId" resultMap="SysUserMap">
|
||||
select
|
||||
user_id, user_name, pwd, real_name, tel, email, salt, remark, create_time, enable, delete_flag, session_id
|
||||
from sys_user
|
||||
where session_id = #{sessionId}
|
||||
and delete_flag = 0
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
Loading…
Reference in New Issue