2025-08-13 12:07:35 +08:00
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
using Volo.Abp.Domain.Services;
|
|
|
|
|
|
using Volo.Abp.Users;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities;
|
2025-08-13 12:07:35 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities.Pay;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
|
|
|
|
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
2025-10-12 16:42:26 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Extensions;
|
2025-08-13 12:07:35 +08:00
|
|
|
|
|
|
|
|
|
|
namespace Yi.Framework.AiHub.Domain.Managers;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 支付管理器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class PayManager : DomainService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ISqlSugarRepository<PayNoticeRecordAggregateRoot, Guid> _payNoticeRepository;
|
|
|
|
|
|
private readonly ICurrentUser _currentUser;
|
|
|
|
|
|
private readonly ISqlSugarRepository<PayOrderAggregateRoot, Guid> _payOrderRepository;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
private readonly ISqlSugarRepository<AiRechargeAggregateRoot, Guid> _rechargeRepository;
|
2025-08-13 18:21:05 +08:00
|
|
|
|
|
2025-08-13 12:07:35 +08:00
|
|
|
|
public PayManager(
|
|
|
|
|
|
ISqlSugarRepository<PayNoticeRecordAggregateRoot, Guid> payNoticeRepository,
|
2025-10-12 20:07:58 +08:00
|
|
|
|
ICurrentUser currentUser,
|
|
|
|
|
|
ISqlSugarRepository<PayOrderAggregateRoot, Guid> payOrderRepository,
|
|
|
|
|
|
ISqlSugarRepository<AiRechargeAggregateRoot, Guid> rechargeRepository)
|
2025-08-13 12:07:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
_payNoticeRepository = payNoticeRepository;
|
|
|
|
|
|
_currentUser = currentUser;
|
|
|
|
|
|
_payOrderRepository = payOrderRepository;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
_rechargeRepository = rechargeRepository;
|
2025-08-13 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建订单
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="goodsType">商品类型</param>
|
|
|
|
|
|
/// <returns>订单信息</returns>
|
|
|
|
|
|
public async Task<PayOrderAggregateRoot> CreateOrderAsync(GoodsTypeEnum goodsType)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 验证用户是否登录
|
|
|
|
|
|
if (!_currentUser.IsAuthenticated)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("用户未登录");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-12 20:07:58 +08:00
|
|
|
|
var userId = _currentUser.GetId();
|
|
|
|
|
|
|
2025-10-12 16:42:26 +08:00
|
|
|
|
// 如果是尊享包商品,需要验证用户是否为VIP
|
|
|
|
|
|
if (goodsType.IsPremiumPackage())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_currentUser.IsAiVip())
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("购买尊享包需要VIP资格,请先开通VIP");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-13 12:07:35 +08:00
|
|
|
|
// 生成订单号
|
|
|
|
|
|
var outTradeNo = GenerateOutTradeNo();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取商品信息
|
|
|
|
|
|
var goodsName = goodsType.GetDisplayName();
|
2025-10-12 20:07:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 计算订单金额(尊享包使用折扣价格,VIP服务使用原价)
|
|
|
|
|
|
decimal totalAmount;
|
|
|
|
|
|
if (goodsType.IsPremiumPackage())
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取用户累加充值金额
|
|
|
|
|
|
var totalRechargeAmount = await GetUserTotalRechargeAmountAsync(userId);
|
|
|
|
|
|
// 使用折扣后的价格
|
|
|
|
|
|
totalAmount = goodsType.GetDiscountedPrice(totalRechargeAmount);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// VIP服务使用原价
|
|
|
|
|
|
totalAmount = goodsType.GetTotalAmount();
|
|
|
|
|
|
}
|
2025-08-13 12:07:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 创建订单实体
|
|
|
|
|
|
var payOrder = new PayOrderAggregateRoot
|
|
|
|
|
|
{
|
|
|
|
|
|
OutTradeNo = outTradeNo,
|
2025-10-12 20:07:58 +08:00
|
|
|
|
UserId = userId,
|
2025-08-13 12:07:35 +08:00
|
|
|
|
UserName = _currentUser.UserName ?? string.Empty,
|
|
|
|
|
|
TotalAmount = totalAmount,
|
|
|
|
|
|
GoodsName = goodsName,
|
|
|
|
|
|
GoodsType = goodsType
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 保存订单
|
|
|
|
|
|
await _payOrderRepository.InsertAsync(payOrder);
|
|
|
|
|
|
|
|
|
|
|
|
return payOrder;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新订单状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="outTradeNo">商户订单号</param>
|
|
|
|
|
|
/// <param name="tradeStatus">交易状态</param>
|
|
|
|
|
|
/// <param name="tradeNo">支付宝交易号</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-08-13 22:19:31 +08:00
|
|
|
|
public async Task<PayOrderAggregateRoot> UpdateOrderStatusAsync(string outTradeNo, TradeStatusEnum tradeStatus, string? tradeNo = null)
|
2025-08-13 12:07:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
var order = await _payOrderRepository.GetFirstAsync(x => x.OutTradeNo == outTradeNo);
|
|
|
|
|
|
if (order == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException($"订单不存在:{outTradeNo}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
order.TradeStatus = tradeStatus;
|
|
|
|
|
|
if (!string.IsNullOrEmpty(tradeNo))
|
|
|
|
|
|
{
|
|
|
|
|
|
order.TradeNo = tradeNo;
|
|
|
|
|
|
}
|
2025-08-13 18:21:05 +08:00
|
|
|
|
|
2025-08-13 12:07:35 +08:00
|
|
|
|
await _payOrderRepository.UpdateAsync(order);
|
2025-08-13 22:19:31 +08:00
|
|
|
|
return order;
|
2025-08-13 12:07:35 +08:00
|
|
|
|
}
|
2025-08-13 18:21:05 +08:00
|
|
|
|
|
2025-08-13 12:07:35 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 记录支付通知
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="notifyData">通知数据</param>
|
2025-08-13 18:21:05 +08:00
|
|
|
|
/// <param name="signStr"></param>
|
2025-08-13 12:07:35 +08:00
|
|
|
|
/// <returns></returns>
|
2025-08-13 18:21:05 +08:00
|
|
|
|
public async Task RecordPayNoticeAsync(Dictionary<string, string> notifyData, string signStr)
|
2025-08-13 12:07:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
var payNotice = new PayNoticeRecordAggregateRoot
|
|
|
|
|
|
{
|
2025-08-13 18:21:05 +08:00
|
|
|
|
NotifyTime = DateTime.Parse(notifyData.GetValueOrDefault("notify_time", string.Empty)),
|
2025-08-13 12:07:35 +08:00
|
|
|
|
TradeNo = notifyData.GetValueOrDefault("trade_no", string.Empty),
|
|
|
|
|
|
OutTradeNo = notifyData.GetValueOrDefault("out_trade_no", string.Empty),
|
|
|
|
|
|
BuyerId = notifyData.GetValueOrDefault("buyer_id", string.Empty),
|
|
|
|
|
|
TradeStatus = ParseTradeStatus(notifyData.GetValueOrDefault("trade_status", string.Empty)),
|
2025-08-13 18:21:05 +08:00
|
|
|
|
TotalAmount = decimal.TryParse(notifyData.GetValueOrDefault("total_amount", "-1"), out var amount)
|
|
|
|
|
|
? amount
|
|
|
|
|
|
: 0,
|
2025-08-13 12:07:35 +08:00
|
|
|
|
NotifyData = JsonSerializer.Serialize(notifyData),
|
2025-08-13 18:21:05 +08:00
|
|
|
|
SignStr = signStr
|
2025-08-13 12:07:35 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await _payNoticeRepository.InsertAsync(payNotice);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 生成商户订单号
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private string GenerateOutTradeNo()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $"YI_{DateTime.Now:yyyyMMddHHmmss}_{Random.Shared.Next(1000, 9999)}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解析交易状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tradeStatus">状态字符串</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private TradeStatusEnum ParseTradeStatus(string tradeStatus)
|
|
|
|
|
|
{
|
2025-08-13 22:19:31 +08:00
|
|
|
|
if (Enum.TryParse<TradeStatusEnum>(tradeStatus, out var result))
|
2025-08-13 12:07:35 +08:00
|
|
|
|
{
|
2025-08-13 22:19:31 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
return TradeStatusEnum.WAIT_TRADE;
|
2025-08-13 12:07:35 +08:00
|
|
|
|
}
|
2025-10-12 20:07:58 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取用户累加充值金额
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="userId">用户ID</param>
|
|
|
|
|
|
/// <returns>累加充值金额</returns>
|
|
|
|
|
|
public async Task<decimal> GetUserTotalRechargeAmountAsync(Guid userId)
|
|
|
|
|
|
{
|
|
|
|
|
|
var totalAmount = await _rechargeRepository
|
|
|
|
|
|
._DbQueryable
|
|
|
|
|
|
.Where(x => x.UserId == userId )
|
|
|
|
|
|
.SumAsync(x => x.RechargeAmount);
|
|
|
|
|
|
|
|
|
|
|
|
return totalAmount;
|
|
|
|
|
|
}
|
2025-10-12 16:42:26 +08:00
|
|
|
|
}
|