diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderInput.cs new file mode 100644 index 00000000..58887ba5 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderInput.cs @@ -0,0 +1,14 @@ +using Yi.Framework.AiHub.Domain.Shared.Enums; + +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Pay; + +/// +/// 创建订单输入DTO +/// +public class CreateOrderInput +{ + /// + /// 商品类型 + /// + public GoodsTypeEnum GoodsType { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderOutput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderOutput.cs new file mode 100644 index 00000000..6edc4efe --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderOutput.cs @@ -0,0 +1,22 @@ +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Pay; + +/// +/// 创建订单输出DTO +/// +public class CreateOrderOutput +{ + /// + /// 订单ID + /// + public Guid OrderId { get; set; } + + /// + /// 商家订单号 + /// + public string OutTradeNo { get; set; } + + /// + /// 支付页面HTML内容 + /// + public string PaymentPageHtml { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/QueryOrderStatusInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/QueryOrderStatusInput.cs new file mode 100644 index 00000000..a9989ff9 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/QueryOrderStatusInput.cs @@ -0,0 +1,12 @@ +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Pay; + +/// +/// 查询订单状态输入DTO +/// +public class QueryOrderStatusInput +{ + /// + /// 商家订单号 + /// + public string OutTradeNo { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/QueryOrderStatusOutput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/QueryOrderStatusOutput.cs new file mode 100644 index 00000000..64b0cbf2 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/QueryOrderStatusOutput.cs @@ -0,0 +1,59 @@ +using Yi.Framework.AiHub.Domain.Shared.Enums; + +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Pay; + +/// +/// 查询订单状态输出DTO +/// +public class QueryOrderStatusOutput +{ + /// + /// 订单ID + /// + public Guid OrderId { get; set; } + + /// + /// 商家订单号 + /// + public string OutTradeNo { get; set; } + + /// + /// 支付宝交易号 + /// + public string? TradeNo { get; set; } + + /// + /// 交易状态 + /// + public TradeStatusEnum TradeStatus { get; set; } + + /// + /// 交易状态描述 + /// + public string TradeStatusDescription { get; set; } + + /// + /// 订单金额 + /// + public decimal TotalAmount { get; set; } + + /// + /// 商品名称 + /// + public string GoodsName { get; set; } + + /// + /// 商品类型 + /// + public GoodsTypeEnum GoodsType { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } + + /// + /// 最后修改时间 + /// + public DateTime? LastModificationTime { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IPayService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IPayService.cs new file mode 100644 index 00000000..1f303501 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IPayService.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Application.Services; +using Yi.Framework.AiHub.Application.Contracts.Dtos.Pay; + +namespace Yi.Framework.AiHub.Application.Contracts.IServices; + +/// +/// 支付服务接口 +/// +public interface IPayService : IApplicationService +{ + /// + /// 创建订单并发起支付 + /// + /// 创建订单输入 + /// 订单创建结果 + Task CreateOrderAsync(CreateOrderInput input); + + /// + /// 支付宝异步通知处理 + /// + /// 表单数据 + /// + Task AlipayNotifyAsync([FromForm] IFormCollection form); + + /// + /// 查询订单状态 + /// + /// 查询订单状态输入 + /// 订单状态信息 + Task QueryOrderStatusAsync([FromQuery] QueryOrderStatusInput input); +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/PayService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/PayService.cs new file mode 100644 index 00000000..c95cdfe0 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/PayService.cs @@ -0,0 +1,168 @@ +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; + +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; + + public PayService( + AlipayManager alipayManager, + PayManager payManager, + ILogger logger, ISqlSugarRepository payOrderRepository) + { + _alipayManager = alipayManager; + _payManager = payManager; + _logger = logger; + _payOrderRepository = payOrderRepository; + } + + /// + /// 创建订单并发起支付 + /// + /// 创建订单输入 + /// 订单创建结果 + [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.OutTradeNo, + order.GoodsName, + order.TotalAmount); + + // 3. 返回结果 + return new CreateOrderOutput + { + OrderId = order.Id, + OutTradeNo = order.OutTradeNo, + PaymentPageHtml = JsonConvert.SerializeObject(paymentPageHtml) + }; + } + + /// + /// 支付宝异步通知处理 + /// + /// 表单数据 + /// + [HttpPost("pay/AlipayNotify")] + public async Task AlipayNotifyAsync([FromForm] IFormCollection form) + { + // 1. 将表单数据转换为字典 + var notifyData = new Dictionary(); + foreach (var item in form) + { + notifyData[item.Key] = item.Value.ToString(); + } + + _logger.LogInformation("收到支付宝回调通知:{NotifyData}", System.Text.Json.JsonSerializer.Serialize(notifyData)); + + // 2. 验证签名 + await _alipayManager.VerifyNotifyAsync(notifyData); + + + // 3. 记录支付通知 + await _payManager.RecordPayNoticeAsync(notifyData); + + // 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); + await _payManager.UpdateOrderStatusAsync(outTradeNo, status, tradeNo); + + _logger.LogInformation("订单状态更新成功,订单号:{OutTradeNo},状态:{TradeStatus}", outTradeNo, tradeStatus); + } + + return "success"; + } + + /// + /// 查询订单状态 + /// + /// 查询订单状态输入 + /// 订单状态信息 + [HttpGet("pay/OrderStatus")] + 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) + { + return tradeStatus switch + { + TradeStatusEnum.WAIT_TRADE => "准备发起", + TradeStatusEnum.WAIT_BUYER_PAY => "等待买家付款", + TradeStatusEnum.TRADE_SUCCESS => "交易成功", + TradeStatusEnum.TRADE_FINISHED => "交易结束", + TradeStatusEnum.TRADE_CLOSED => "交易关闭", + _ => "未知状态" + }; + } + + /// + /// 解析交易状态 + /// + /// 状态字符串 + /// + private TradeStatusEnum ParseTradeStatus(string tradeStatus) + { + return tradeStatus switch + { + "WAIT_BUYER_PAY" => TradeStatusEnum.WAIT_BUYER_PAY, + "TRADE_SUCCESS" => TradeStatusEnum.TRADE_SUCCESS, + "TRADE_FINISHED" => TradeStatusEnum.TRADE_FINISHED, + "TRADE_CLOSED" => TradeStatusEnum.TRADE_CLOSED, + _ => TradeStatusEnum.WAIT_TRADE + }; + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs new file mode 100644 index 00000000..082e35e0 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs @@ -0,0 +1,92 @@ +using System; +using System.Reflection; + +namespace Yi.Framework.AiHub.Domain.Shared.Enums; + +/// +/// 价格特性 +/// +[AttributeUsage(AttributeTargets.Field)] +public class PriceAttribute : Attribute +{ + public decimal Price { get; } + + public PriceAttribute(double price) + { + Price = (decimal)price; + } +} + +/// +/// 显示名称特性 +/// +[AttributeUsage(AttributeTargets.Field)] +public class DisplayNameAttribute : Attribute +{ + public string DisplayName { get; } + + public DisplayNameAttribute(string displayName) + { + DisplayName = displayName; + } +} + +/// +/// 商品枚举 +/// +public enum GoodsTypeEnum +{ + [Price(29.9)] + [DisplayName("意心Vip会员1个月")] + YiXinVip1 = 1, + + [Price(80.7)] + [DisplayName("意心Vip会员3个月")] + YiXinVip3 = 3, + + [Price(143.9)] + [DisplayName("意心Vip会员6个月")] + YiXinVip6 = 6, + + [Price(199.9)] + [DisplayName("意心Vip会员10个月")] + YiXinVip10 = 10 +} + +public static class GoodsTypeEnumExtensions +{ + /// + /// 获取商品总金额 + /// + /// 商品类型 + /// 总金额 + public static decimal GetTotalAmount(this GoodsTypeEnum goodsType) + { + var fieldInfo = goodsType.GetType().GetField(goodsType.ToString()); + var priceAttribute = fieldInfo?.GetCustomAttribute(); + return priceAttribute?.Price ?? 0m; + } + + /// + /// 获取商品价格描述 + /// + /// 商品类型 + /// 价格描述 + public static string GetPriceDescription(this GoodsTypeEnum goodsType) + { + var price = goodsType.GetTotalAmount(); + return $"¥{price:F1}"; + } + + /// + /// 获取商品名称 + /// + /// 商品类型 + /// 商品名称 + public static string GetDisplayName(this GoodsTypeEnum goodsType) + { + var fieldInfo = goodsType.GetType().GetField(goodsType.ToString()); + var displayNameAttribute = fieldInfo?.GetCustomAttribute(); + return displayNameAttribute?.DisplayName ?? goodsType.ToString(); + } +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/TradeStatusEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/TradeStatusEnum.cs new file mode 100644 index 00000000..9309ba81 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/TradeStatusEnum.cs @@ -0,0 +1,29 @@ +namespace Yi.Framework.AiHub.Domain.Shared.Enums; + +public enum TradeStatusEnum +{ + /// + /// 准备发起 + /// + WAIT_TRADE = 0, + + /// + /// 交易创建 + /// + WAIT_BUYER_PAY = 10, + + /// + /// 交易关闭 + /// + TRADE_CLOSED = 20, + + /// + /// 交易成功 + /// + TRADE_SUCCESS = 100, + + /// + /// 交易结束 + /// + TRADE_FINISHED = -10 +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayException.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayException.cs new file mode 100644 index 00000000..82a26d4b --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayException.cs @@ -0,0 +1,10 @@ +using Microsoft.Extensions.Logging; + +namespace Yi.Framework.AiHub.Domain.Alipay; + +public class AlipayException:UserFriendlyException +{ + public AlipayException(string message, string? code = null, string? details = null, Exception? innerException = null, LogLevel logLevel = LogLevel.Warning) : base(message, code, details, innerException, logLevel) + { + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayManager.cs new file mode 100644 index 00000000..01fbf483 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayManager.cs @@ -0,0 +1,65 @@ +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Kernel.Util; +using Alipay.EasySDK.Payment.Page.Models; +using Microsoft.Extensions.Logging; +using Volo.Abp.Domain.Services; + +namespace Yi.Framework.AiHub.Domain.Alipay; + +public class AlipayManager : DomainService +{ + private readonly ILogger _logger; + + public AlipayManager(ILogger logger) + { + _logger = logger; + } + + /// + /// 统一Page支付 + /// + /// + /// + public Task PaymentPageAsync(string productName, string orderNumber, decimal totalAmount) + { + try + { + // 2. 发起API调用(以创建当面付收款二维码为例) + var response = Factory.Payment.Page() + .Pay(productName, orderNumber, totalAmount.ToString(), "https://ccnetcore.com/pay/sucess"); + // 3. 处理响应或异常 + if (ResponseChecker.Success(response)) + { + _logger.LogInformation($"支付宝:PaymentPage发起调用成功,返回内容:{response.Body}"); + //插入数据库 + + return Task.FromResult(response); + } + else + { + throw new AlipayException($"支付宝:PaymentPage发起调用失败,原因:{response.Body}"); + } + } + catch (Exception ex) + { + throw new AlipayException($"支付宝:PaymentPage发起调用错误,原因:{ex.Message}", innerException: ex); + } + } + + /// + /// 通知验签 + /// + /// + /// + /// + public Task VerifyNotifyAsync(Dictionary form) + { + var result = Factory.Payment.Common().VerifyNotify(form); + if (result == false) + { + throw new AlipayException($"支付宝支付,验签失败"); + } + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Pay/PayNoticeRecordAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Pay/PayNoticeRecordAggregateRoot.cs new file mode 100644 index 00000000..b027788b --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Pay/PayNoticeRecordAggregateRoot.cs @@ -0,0 +1,58 @@ +using SqlSugar; +using Volo.Abp.Domain.Entities.Auditing; +using Yi.Framework.AiHub.Domain.Shared.Enums; + +namespace Yi.Framework.AiHub.Domain.Entities.Pay; + +/// +/// 支付通知记录 +/// +[SugarTable("Ai_PayNoticeRecord")] +public class PayNoticeRecordAggregateRoot: FullAuditedAggregateRoot +{ + /// + /// 通知时间 + /// + public DateTime NotifyTime { get; set; } + + /// + /// 支付宝交易号 + /// + public string TradeNo { get; set; } + + /// + /// 商家订单号 + /// + public string OutTradeNo { get; set; } + + /// + /// 买家openId + /// + public string BuyerId { get; set; } + + /// + /// 订单状态 + /// + public TradeStatusEnum TradeStatus { get; set; } + + /// + /// 订单金额 + /// + public decimal TotalAmount { get; set; } + + /// + /// 实收金额 + /// + public decimal ReceiptAmount { get; set; } + + /// + /// 用户支付金额 + /// + public decimal BuyerPayAmount { get; set; } + + /// + /// 通知原始数据 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)] + public string NotifyData { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Pay/PayOrderAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Pay/PayOrderAggregateRoot.cs new file mode 100644 index 00000000..a5b14cfa --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Pay/PayOrderAggregateRoot.cs @@ -0,0 +1,52 @@ +using SqlSugar; +using Volo.Abp.Domain.Entities.Auditing; +using Yi.Framework.AiHub.Domain.Shared.Enums; + +namespace Yi.Framework.AiHub.Domain.Entities.Pay; + +/// +/// 支付订单 +/// +[SugarTable("Ai_PayOrder")] +public class PayOrderAggregateRoot : FullAuditedAggregateRoot +{ + /// + /// 商家订单号 + /// + public string OutTradeNo { get; set; } + + /// + /// 下单用户 + /// + public Guid UserId { get; set; } + + /// + /// 下单用户名称 + /// + public string UserName { get; set; } + + /// + /// 订单状态 + /// + public TradeStatusEnum TradeStatus { get; set; } = TradeStatusEnum.WAIT_TRADE; + + /// + /// 订单金额 + /// + public decimal TotalAmount { get; set; } + + /// + /// 商品类型 + /// + public GoodsTypeEnum GoodsType { get; set; } + + /// + /// 商品名称 + /// + public string GoodsName { get; set; } + + /// + /// 支付宝交易号 + /// + public string? TradeNo { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PayManager.cs new file mode 100644 index 00000000..d6d67f94 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PayManager.cs @@ -0,0 +1,137 @@ +using System.Text.Json; +using Volo.Abp.Domain.Services; +using Volo.Abp.Users; +using Yi.Framework.AiHub.Domain.Entities.Pay; +using Yi.Framework.AiHub.Domain.Shared.Enums; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.AiHub.Domain.Managers; + +/// +/// 支付管理器 +/// +public class PayManager : DomainService +{ + + private readonly ISqlSugarRepository _payNoticeRepository; + private readonly ICurrentUser _currentUser; + private readonly ISqlSugarRepository _payOrderRepository; + public PayManager( + ISqlSugarRepository payNoticeRepository, + ICurrentUser currentUser, ISqlSugarRepository payOrderRepository) + { + _payNoticeRepository = payNoticeRepository; + _currentUser = currentUser; + _payOrderRepository = payOrderRepository; + } + + /// + /// 创建订单 + /// + /// 商品类型 + /// 订单信息 + public async Task CreateOrderAsync(GoodsTypeEnum goodsType) + { + // 验证用户是否登录 + if (!_currentUser.IsAuthenticated) + { + throw new UserFriendlyException("用户未登录"); + } + + // 生成订单号 + var outTradeNo = GenerateOutTradeNo(); + + // 获取商品信息 + var goodsName = goodsType.GetDisplayName(); + var totalAmount = goodsType.GetTotalAmount(); + + // 创建订单实体 + var payOrder = new PayOrderAggregateRoot + { + OutTradeNo = outTradeNo, + UserId = _currentUser.GetId(), + UserName = _currentUser.UserName ?? string.Empty, + TotalAmount = totalAmount, + GoodsName = goodsName, + GoodsType = goodsType + }; + + // 保存订单 + await _payOrderRepository.InsertAsync(payOrder); + + return payOrder; + } + + /// + /// 更新订单状态 + /// + /// 商户订单号 + /// 交易状态 + /// 支付宝交易号 + /// + public async Task UpdateOrderStatusAsync(string outTradeNo, TradeStatusEnum tradeStatus, string? tradeNo = null) + { + 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; + } + order.LastModificationTime = DateTime.Now; + + await _payOrderRepository.UpdateAsync(order); + } + + + /// + /// 记录支付通知 + /// + /// 通知数据 + /// + public async Task RecordPayNoticeAsync(Dictionary notifyData) + { + var payNotice = new PayNoticeRecordAggregateRoot + { + NotifyTime =DateTime.Parse(notifyData.GetValueOrDefault("notify_time", string.Empty)) , + 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)), + TotalAmount = decimal.TryParse(notifyData.GetValueOrDefault("total_amount", "-1"), out var amount) ? amount : 0, + NotifyData = JsonSerializer.Serialize(notifyData), + }; + + await _payNoticeRepository.InsertAsync(payNotice); + } + + /// + /// 生成商户订单号 + /// + /// + private string GenerateOutTradeNo() + { + return $"YI_{DateTime.Now:yyyyMMddHHmmss}_{Random.Shared.Next(1000, 9999)}"; + } + + /// + /// 解析交易状态 + /// + /// 状态字符串 + /// + private TradeStatusEnum ParseTradeStatus(string tradeStatus) + { + return tradeStatus switch + { + "WAIT_BUYER_PAY" => TradeStatusEnum.WAIT_BUYER_PAY, + "TRADE_SUCCESS" => TradeStatusEnum.TRADE_SUCCESS, + "TRADE_FINISHED" => TradeStatusEnum.TRADE_FINISHED, + "TRADE_CLOSED" => TradeStatusEnum.TRADE_CLOSED, + _ => TradeStatusEnum.WAIT_TRADE + }; + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs index 7557b774..31288d35 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs @@ -85,27 +85,6 @@ namespace Yi.Framework.AiHub.Domain public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) { - try - { - // 2. 发起API调用(以创建当面付收款二维码为例) - var response = Factory.Payment.Page() - .Pay("YiXin Ai Vip", "2234567234891", "0.01","https://ccnetcore.com/pay/Alipay/test"); - // 3. 处理响应或异常 - if (ResponseChecker.Success(response)) - { - Console.WriteLine("调用成功"); - Console.WriteLine(response.Body); - } - else - { - Console.WriteLine("调用失败,原因:" + response.Body); - } - } - catch (Exception ex) - { - Console.WriteLine("调用遭遇异常,原因:" + ex.Message); - throw ex; - } } } } \ No newline at end of file