using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Services; using Yi.Framework.AiHub.Domain.Alipay; using Yi.Framework.AiHub.Domain.Managers; using Yi.Framework.AiHub.Application.Contracts.Dtos.Pay; using Yi.Framework.AiHub.Domain.Shared.Enums; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Yi.Framework.AiHub.Application.Contracts.IServices; using Volo.Abp; using Yi.Framework.AiHub.Domain.Entities.Pay; using Yi.Framework.SqlSugarCore.Abstractions; using System.ComponentModel; using System.Reflection; using Yi.Framework.AiHub.Application.Contracts.Dtos.Recharge; namespace Yi.Framework.AiHub.Application.Services; /// /// 支付服务 /// public class PayService : ApplicationService, IPayService { private readonly AlipayManager _alipayManager; private readonly PayManager _payManager; private readonly ILogger _logger; private readonly ISqlSugarRepository _payOrderRepository; private readonly IRechargeService _rechargeService; public PayService( AlipayManager alipayManager, PayManager payManager, ILogger logger, ISqlSugarRepository payOrderRepository, IRechargeService rechargeService) { _alipayManager = alipayManager; _payManager = payManager; _logger = logger; _payOrderRepository = payOrderRepository; _rechargeService = rechargeService; } /// /// 创建订单并发起支付 /// /// 创建订单输入 /// 订单创建结果 [Authorize] [HttpPost("pay/Order")] public async Task CreateOrderAsync(CreateOrderInput input) { // 1. 通过PayManager创建订单 var order = await _payManager.CreateOrderAsync(input.GoodsType); // 2. 通过AlipayManager发起页面支付 var paymentPageHtml = await _alipayManager.PaymentPageAsync( order.GoodsName, order.OutTradeNo, order.TotalAmount, input.ReturnUrl); // 3. 返回结果 return new CreateOrderOutput { OrderId = order.Id, OutTradeNo = order.OutTradeNo, PaymentPageHtml = paymentPageHtml.Body }; } /// /// 支付宝异步通知处理 /// /// 表单数据 /// [HttpPost("pay/AlipayNotify")] [AllowAnonymous] public async Task AlipayNotifyAsync([FromForm] IFormCollection form) { // 1. 将表单数据转换为字典,保持原始顺序 var notifyData = new Dictionary(); foreach (var item in form) { notifyData[item.Key] = item.Value.ToString(); } var signStr = string.Join("&", notifyData.Select(kv => $"{kv.Key}={kv.Value}")); _logger.LogInformation($"收到支付宝回调通知:{signStr}"); // 2. 验证签名 await _alipayManager.VerifyNotifyAsync(notifyData); // 3. 记录支付通知 await _payManager.RecordPayNoticeAsync(notifyData, signStr); // 4. 更新订单状态 var outTradeNo = notifyData.GetValueOrDefault("out_trade_no", string.Empty); var tradeStatus = notifyData.GetValueOrDefault("trade_status", string.Empty); var tradeNo = notifyData.GetValueOrDefault("trade_no", string.Empty); if (!string.IsNullOrEmpty(outTradeNo) && !string.IsNullOrEmpty(tradeStatus)) { var status = ParseTradeStatus(tradeStatus); var order = await _payManager.UpdateOrderStatusAsync(outTradeNo, status, tradeNo); _logger.LogInformation("订单状态更新成功,订单号:{OutTradeNo},状态:{TradeStatus}", outTradeNo, tradeStatus); //5.充值Vip await _rechargeService.RechargeVipAsync(new RechargeCreateInput { UserId = order.UserId, RechargeAmount = order.TotalAmount, Content = order.GoodsName, Months = order.GoodsType.GetValidMonths(), Remark = "自助充值", ContactInfo = null }); } else { throw new AlipayException($"回调格式错误"); } return "success"; } /// /// 查询订单状态 /// /// 查询订单状态输入 /// 订单状态信息 [HttpGet("pay/OrderStatus")] [Authorize] public async Task QueryOrderStatusAsync([FromQuery] QueryOrderStatusInput input) { // 通过PayManager查询订单 var order = await _payOrderRepository.GetFirstAsync(x => x.OutTradeNo == input.OutTradeNo); if (order == null) { throw new UserFriendlyException($"订单不存在:{input.OutTradeNo}"); } return new QueryOrderStatusOutput { OrderId = order.Id, OutTradeNo = order.OutTradeNo, TradeNo = order.TradeNo, TradeStatus = order.TradeStatus, TradeStatusDescription = GetTradeStatusDescription(order.TradeStatus), TotalAmount = order.TotalAmount, GoodsName = order.GoodsName, GoodsType = order.GoodsType, CreationTime = order.CreationTime, LastModificationTime = order.LastModificationTime }; } /// /// 获取交易状态描述 /// /// 交易状态 /// 状态描述 private string GetTradeStatusDescription(TradeStatusEnum tradeStatus) { var fieldInfo = tradeStatus.GetType().GetField(tradeStatus.ToString()); var descriptionAttribute = fieldInfo?.GetCustomAttribute(); return descriptionAttribute?.Description ?? "未知状态"; } /// /// 解析交易状态 /// /// 状态字符串 /// private TradeStatusEnum ParseTradeStatus(string tradeStatus) { if (Enum.TryParse(tradeStatus, out var result)) { return result; } return TradeStatusEnum.WAIT_TRADE; } }