From 1bd6683cb8b8ca0a478c0ddbc594cc64ffa144c4 Mon Sep 17 00:00:00 2001 From: zpc Date: Sat, 21 Feb 2026 13:28:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(payment):=20=E6=94=AF=E6=8C=81=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98V3=E8=AF=81=E4=B9=A6PEM=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E5=AD=98=E5=82=A8=E5=88=B0=E6=95=B0=E6=8D=AE=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WechatPayMerchantConfig 新增 PrivateKeyContent/WechatPublicKeyContent 字段 - WechatPayV3Service 新增 ResolvePrivateKey/ResolvePublicKey 优先读数据库内容 - 后台管理页面改为文本域粘贴PEM内容,路径作为备选 - 完全向后兼容,原文件路径方式依然可用 - 迁移服务器只需在后台重新配置即可,无需拷贝证书文件 --- .../Models/Config/ConfigModels.cs | 12 + .../Models/Config/WeixinPaySetting.cs | 12 + .../admin-web/src/api/system/config.ts | 4 + .../src/views/system/config/payment.vue | 38 +- .../Services/WechatPayConfigService.cs | 8 +- .../Services/WechatPayV3Service.cs | 70 +++- .../Models/Payment/PaymentModels.cs | 356 +++++++++--------- 7 files changed, 309 insertions(+), 191 deletions(-) diff --git a/server/MiAssessment/src/MiAssessment.Admin.Business/Models/Config/ConfigModels.cs b/server/MiAssessment/src/MiAssessment.Admin.Business/Models/Config/ConfigModels.cs index 3cb289f..3361c79 100644 --- a/server/MiAssessment/src/MiAssessment.Admin.Business/Models/Config/ConfigModels.cs +++ b/server/MiAssessment/src/MiAssessment.Admin.Business/Models/Config/ConfigModels.cs @@ -108,6 +108,12 @@ public class WeixinPayMerchant [JsonPropertyName("private_key_path")] public string? PrivateKeyPath { get; set; } + /// + /// 商户私钥PEM内容(V3版本使用,优先级高于路径) + /// + [JsonPropertyName("private_key_content")] + public string? PrivateKeyContent { get; set; } + /// /// 微信支付公钥ID(V3版本使用) /// @@ -119,6 +125,12 @@ public class WeixinPayMerchant /// [JsonPropertyName("wechat_public_key_path")] public string? WechatPublicKeyPath { get; set; } + + /// + /// 微信支付公钥PEM内容(V3版本使用,优先级高于路径) + /// + [JsonPropertyName("wechat_public_key_content")] + public string? WechatPublicKeyContent { get; set; } } diff --git a/server/MiAssessment/src/MiAssessment.Admin/Models/Config/WeixinPaySetting.cs b/server/MiAssessment/src/MiAssessment.Admin/Models/Config/WeixinPaySetting.cs index 6adf79e..59c2c8e 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/Models/Config/WeixinPaySetting.cs +++ b/server/MiAssessment/src/MiAssessment.Admin/Models/Config/WeixinPaySetting.cs @@ -61,6 +61,12 @@ public class WeixinPayMerchant [JsonPropertyName("private_key_path")] public string? PrivateKeyPath { get; set; } + /// + /// 商户私钥PEM内容(优先级高于路径) + /// + [JsonPropertyName("private_key_content")] + public string? PrivateKeyContent { get; set; } + /// /// 微信支付公钥ID /// @@ -73,6 +79,12 @@ public class WeixinPayMerchant [JsonPropertyName("wechat_public_key_path")] public string? WechatPublicKeyPath { get; set; } + /// + /// 微信支付公钥PEM内容(优先级高于路径) + /// + [JsonPropertyName("wechat_public_key_content")] + public string? WechatPublicKeyContent { get; set; } + /// /// API密钥(V2版本使用) /// diff --git a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts index 4020ecc..2f0cbcd 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts +++ b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts @@ -125,10 +125,14 @@ export interface WeixinPayMerchant { cert_serial_no?: string /** 商户私钥文件路径 */ private_key_path?: string + /** 商户私钥PEM内容(优先级高于路径) */ + private_key_content?: string /** 微信支付公钥ID */ wechat_public_key_id?: string /** 微信支付公钥文件路径 */ wechat_public_key_path?: string + /** 微信支付公钥PEM内容(优先级高于路径) */ + wechat_public_key_content?: string /** API密钥(V2) */ api_key?: string /** 证书路径(V2) */ diff --git a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/payment.vue b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/payment.vue index 2a2ad33..f13d3d1 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/payment.vue +++ b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/payment.vue @@ -99,19 +99,43 @@ - - - - - + + 证书配置(二选一:粘贴内容 或 填写服务器路径) + + + + +
推荐方式:直接粘贴PEM文件内容,迁移服务器无需重新上传证书文件
+
+ + +
仅当未填写私钥内容时使用
+
+ + + + +
推荐方式:直接粘贴PEM文件内容
+
- + +
仅当未填写公钥内容时使用
@@ -205,8 +229,10 @@ function addMerchant() { api_v3_key: '', cert_serial_no: '', private_key_path: '', + private_key_content: '', wechat_public_key_id: '', wechat_public_key_path: '', + wechat_public_key_content: '', api_key: '', cert_path: '', is_enabled: '1' diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayConfigService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayConfigService.cs index 695f32e..a4a9808 100644 --- a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayConfigService.cs +++ b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayConfigService.cs @@ -71,8 +71,10 @@ public class WechatPayConfigService : IWechatPayConfigService ApiV3Key = m.ApiV3Key, CertSerialNo = m.CertSerialNo, PrivateKeyPath = m.PrivateKeyPath, + PrivateKeyContent = m.PrivateKeyContent, WechatPublicKeyId = m.WechatPublicKeyId, WechatPublicKeyPath = m.WechatPublicKeyPath, + WechatPublicKeyContent = m.WechatPublicKeyContent, NotifyUrl = !string.IsNullOrEmpty(m.NotifyUrl) ? m.NotifyUrl : "https://api.zfunbox.cn/api/notify" }); } @@ -215,8 +217,10 @@ public class WechatPayConfigService : IWechatPayConfigService ApiV3Key = selectedMerchant.ApiV3Key, CertSerialNo = selectedMerchant.CertSerialNo, PrivateKeyPath = selectedMerchant.PrivateKeyPath, + PrivateKeyContent = selectedMerchant.PrivateKeyContent, WechatPublicKeyId = selectedMerchant.WechatPublicKeyId, - WechatPublicKeyPath = selectedMerchant.WechatPublicKeyPath + WechatPublicKeyPath = selectedMerchant.WechatPublicKeyPath, + WechatPublicKeyContent = selectedMerchant.WechatPublicKeyContent }; } @@ -304,8 +308,10 @@ public class WechatPayConfigService : IWechatPayConfigService [JsonPropertyName("api_v3_key")] public string? ApiV3Key { get; set; } [JsonPropertyName("cert_serial_no")] public string? CertSerialNo { get; set; } [JsonPropertyName("private_key_path")] public string? PrivateKeyPath { get; set; } + [JsonPropertyName("private_key_content")] public string? PrivateKeyContent { get; set; } [JsonPropertyName("wechat_public_key_id")] public string? WechatPublicKeyId { get; set; } [JsonPropertyName("wechat_public_key_path")] public string? WechatPublicKeyPath { get; set; } + [JsonPropertyName("wechat_public_key_content")] public string? WechatPublicKeyContent { get; set; } [JsonPropertyName("notify_url")] public string? NotifyUrl { get; set; } } private class DbWeixinPayConfig diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs index 708cea7..7ca56b3 100644 --- a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs +++ b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs @@ -90,7 +90,7 @@ public class WechatPayV3Service : IWechatPayV3Service // 验证 V3 配置 if (string.IsNullOrEmpty(merchantConfig.ApiV3Key) || string.IsNullOrEmpty(merchantConfig.CertSerialNo) || - string.IsNullOrEmpty(merchantConfig.PrivateKeyPath)) + (string.IsNullOrEmpty(merchantConfig.PrivateKeyContent) && string.IsNullOrEmpty(merchantConfig.PrivateKeyPath))) { _logger.LogError("V3 配置不完整: MchId={MchId}", merchantConfig.MchId); return new WechatPayResult { Status = 0, Msg = "V3 支付配置不完整" }; @@ -98,11 +98,11 @@ public class WechatPayV3Service : IWechatPayV3Service _logger.LogDebug("使用 V3 商户配置: MchId={MchId}, AppId={AppId}", merchantConfig.MchId, merchantConfig.AppId); - // 3. 读取私钥 - var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath); + // 3. 读取私钥(优先使用数据库中的PEM内容) + var privateKey = ResolvePrivateKey(merchantConfig); if (string.IsNullOrEmpty(privateKey)) { - _logger.LogError("读取私钥失败: Path={Path}", merchantConfig.PrivateKeyPath); + _logger.LogError("读取私钥失败: MchId={MchId}", merchantConfig.MchId); return new WechatPayResult { Status = 0, Msg = "读取商户私钥失败" }; } @@ -211,7 +211,7 @@ public class WechatPayV3Service : IWechatPayV3Service _logger.LogInformation("开始查询 V3 订单: OrderNo={OrderNo}", orderNo); var merchantConfig = _configService.GetMerchantByOrderNo(orderNo); - var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath!); + var privateKey = ResolvePrivateKey(merchantConfig); var url = $"/v3/pay/transactions/out-trade-no/{orderNo}?mchid={merchantConfig.MchId}"; var fullUrl = string.Format(V3_QUERY_URL, orderNo) + $"?mchid={merchantConfig.MchId}"; @@ -274,7 +274,7 @@ public class WechatPayV3Service : IWechatPayV3Service _logger.LogInformation("开始关闭 V3 订单: OrderNo={OrderNo}", orderNo); var merchantConfig = _configService.GetMerchantByOrderNo(orderNo); - var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath!); + var privateKey = ResolvePrivateKey(merchantConfig); var url = $"/v3/pay/transactions/out-trade-no/{orderNo}/close"; var fullUrl = string.Format(V3_CLOSE_URL, orderNo); @@ -337,7 +337,7 @@ public class WechatPayV3Service : IWechatPayV3Service request.OrderNo, request.RefundNo, request.RefundAmount); var merchantConfig = _configService.GetMerchantByOrderNo(request.OrderNo); - var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath!); + var privateKey = ResolvePrivateKey(merchantConfig); var apiRequest = new WechatPayV3RefundApiRequest { @@ -451,9 +451,9 @@ public class WechatPayV3Service : IWechatPayV3Service // 获取商户配置 var merchantConfig = _configService.GetDefaultConfig(); - if (string.IsNullOrEmpty(merchantConfig.WechatPublicKeyPath)) + if (string.IsNullOrEmpty(merchantConfig.WechatPublicKeyContent) && string.IsNullOrEmpty(merchantConfig.WechatPublicKeyPath)) { - _logger.LogError("微信支付公钥路径未配置"); + _logger.LogError("微信支付公钥未配置(内容和路径均为空)"); return false; } @@ -467,10 +467,10 @@ public class WechatPayV3Service : IWechatPayV3Service // 继续验证,因为可能是微信更换了公钥 } - var publicKey = ReadPublicKey(merchantConfig.WechatPublicKeyPath); + var publicKey = ResolvePublicKey(merchantConfig); if (string.IsNullOrEmpty(publicKey)) { - _logger.LogError("读取微信支付公钥失败: Path={Path}", merchantConfig.WechatPublicKeyPath); + _logger.LogError("读取微信支付公钥失败: MchId={MchId}", merchantConfig.MchId); return false; } @@ -853,6 +853,54 @@ public class WechatPayV3Service : IWechatPayV3Service } } + /// + /// 解析商户私钥:优先使用数据库中的PEM内容,fallback到文件路径 + /// + /// 商户配置 + /// 私钥PEM内容 + private string ResolvePrivateKey(WechatPayMerchantConfig config) + { + // 优先使用数据库中存储的PEM内容 + if (!string.IsNullOrEmpty(config.PrivateKeyContent)) + { + _logger.LogDebug("使用数据库中的商户私钥内容"); + return config.PrivateKeyContent; + } + + // fallback到文件路径 + if (!string.IsNullOrEmpty(config.PrivateKeyPath)) + { + return ReadPrivateKey(config.PrivateKeyPath); + } + + _logger.LogError("商户私钥未配置(内容和路径均为空): MchId={MchId}", config.MchId); + return string.Empty; + } + + /// + /// 解析微信支付公钥:优先使用数据库中的PEM内容,fallback到文件路径 + /// + /// 商户配置 + /// 公钥PEM内容 + private string ResolvePublicKey(WechatPayMerchantConfig config) + { + // 优先使用数据库中存储的PEM内容 + if (!string.IsNullOrEmpty(config.WechatPublicKeyContent)) + { + _logger.LogDebug("使用数据库中的微信支付公钥内容"); + return config.WechatPublicKeyContent; + } + + // fallback到文件路径 + if (!string.IsNullOrEmpty(config.WechatPublicKeyPath)) + { + return ReadPublicKey(config.WechatPublicKeyPath); + } + + _logger.LogError("微信支付公钥未配置(内容和路径均为空): MchId={MchId}", config.MchId); + return string.Empty; + } + /// /// 截断商品描述(V3 限制最大 127 字符) /// diff --git a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentModels.cs b/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentModels.cs index 1a04fc2..b36cccb 100644 --- a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentModels.cs +++ b/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentModels.cs @@ -5,114 +5,114 @@ namespace MiAssessment.Model.Models.Payment; #region Wechat Pay Request/Response Models /// -/// ΢֧΢֧Э飬snake_case +/// ΢��֧������΢��֧��Э�飬����snake_case�� /// public class WechatPayRequest { /// - /// + /// ������ /// [JsonPropertyName("order_no")] public string OrderNo { get; set; } = string.Empty; /// - /// ֧λԪ + /// ֧������λ��Ԫ�� /// [JsonPropertyName("amount")] public decimal Amount { get; set; } /// - /// Ʒ + /// ��Ʒ���� /// [JsonPropertyName("body")] public string Body { get; set; } = string.Empty; /// - /// ݣֶͣ + /// �������ݣ��������ֶ������ͣ� /// [JsonPropertyName("attach")] public string Attach { get; set; } = string.Empty; /// - /// ûOpenId + /// �û�OpenId /// [JsonPropertyName("open_id")] public string OpenId { get; set; } = string.Empty; /// - /// ûID + /// �û�ID /// [JsonPropertyName("user_id")] public long UserId { get; set; } } /// -/// ΢֧΢֧Э飬snake_case +/// ΢��֧�������΢��֧��Э�飬����snake_case�� /// public class WechatPayResult { /// - /// ״̬1=ɹ0=ʧ + /// ״̬��1=�ɹ���0=ʧ�� /// [JsonPropertyName("status")] public int Status { get; set; } /// - /// Ϣ + /// ��Ϣ /// [JsonPropertyName("msg")] public string Msg { get; set; } = string.Empty; /// - /// ֧ + /// ֧������ /// [JsonPropertyName("data")] public WechatPayData? Data { get; set; } } /// -/// ΢֧ݣظǰ˵֧΢JS-SDKЭ飩 +/// ΢��֧�����ݣ����ظ�ǰ�˵���֧����΢��JS-SDKЭ�飩 /// public class WechatPayData { /// - /// ӦID + /// Ӧ��ID /// [JsonPropertyName("appId")] public string AppId { get; set; } = string.Empty; /// - /// ʱ + /// ʱ��� /// [JsonPropertyName("timeStamp")] public string TimeStamp { get; set; } = string.Empty; /// - /// ַ + /// ����ַ��� /// [JsonPropertyName("nonceStr")] public string NonceStr { get; set; } = string.Empty; /// - /// Ԥ֧׻Ựʶ + /// Ԥ֧�����׻Ự��ʶ /// [JsonPropertyName("package")] public string Package { get; set; } = string.Empty; /// - /// ǩ + /// ǩ������ /// [JsonPropertyName("signType")] public string SignType { get; set; } = "MD5"; /// - /// ǩ + /// ǩ�� /// [JsonPropertyName("paySign")] public string PaySign { get; set; } = string.Empty; /// - /// Ƿ΢Ż1=ǣ0= + /// �Ƿ�΢�Ż�����1=�ǣ�0=�� /// [JsonPropertyName("is_weixin")] public int IsWeixin { get; set; } @@ -123,148 +123,148 @@ public class WechatPayData #region Payment Notify Models /// -/// ֧ص֪ͨڲʹãֱӷǰˣ +/// ֧���ص�֪ͨ������ڲ�ʹ�ã���ֱ�ӷ���ǰ�ˣ� /// public class NotifyResult { /// - /// Ƿɹ + /// �Ƿ�ɹ� /// public bool Success { get; set; } /// - /// Ϣ + /// ��Ϣ /// public string Message { get; set; } = string.Empty; /// - /// XMLӦݣظ΢ V2 + /// XML��Ӧ���ݣ����ظ�΢�� V2�� /// public string XmlResponse { get; set; } = string.Empty; /// - /// JSONӦݣظ΢ V3 + /// JSON��Ӧ���ݣ����ظ�΢�� V3�� /// public string JsonResponse { get; set; } = string.Empty; /// - /// ţҵ + /// �����ţ�����ҵ������ /// public string? OrderNo { get; set; } /// - /// ݣͣҵ·ɣ + /// �������ݣ��������ͣ�����ҵ��·�ɣ� /// public string? Attach { get; set; } /// - /// صݣҵ + /// �ص����ݣ�����ҵ������ /// public WechatNotifyData? NotifyData { get; set; } } /// -/// ΢֧صݣ΢֧Э飬ڲʹã +/// ΢��֧���ص����ݣ�΢��֧��Э�飬�ڲ�ʹ�ã� /// public class WechatNotifyData { /// - /// ״̬ + /// ����״̬�� /// public string ReturnCode { get; set; } = string.Empty; /// - /// Ϣ + /// ������Ϣ /// public string ReturnMsg { get; set; } = string.Empty; /// - /// ҵ + /// ҵ���� /// public string ResultCode { get; set; } = string.Empty; /// - /// + /// ������� /// public string ErrCode { get; set; } = string.Empty; /// - /// + /// ����������� /// public string ErrCodeDes { get; set; } = string.Empty; /// - /// ӦID + /// Ӧ��ID /// public string AppId { get; set; } = string.Empty; /// - /// ̻ + /// �̻��� /// public string MchId { get; set; } = string.Empty; /// - /// ַ + /// ����ַ��� /// public string NonceStr { get; set; } = string.Empty; /// - /// ǩ + /// ǩ�� /// public string Sign { get; set; } = string.Empty; /// - /// ǩ + /// ǩ������ /// public string SignType { get; set; } = string.Empty; /// - /// ûʶ + /// �û���ʶ /// public string OpenId { get; set; } = string.Empty; /// - /// + /// �������� /// public string TradeType { get; set; } = string.Empty; /// - /// + /// �������� /// public string BankType { get; set; } = string.Empty; /// - /// λ֣ + /// ��������λ���֣� /// public int TotalFee { get; set; } /// - /// + /// �������� /// public string FeeType { get; set; } = string.Empty; /// - /// ֽ֧λ֣ + /// �ֽ�֧������λ���֣� /// public int CashFee { get; set; } /// - /// ΢֧ + /// ΢��֧�������� /// public string TransactionId { get; set; } = string.Empty; /// - /// ̻ + /// �̻������� /// public string OutTradeNo { get; set; } = string.Empty; /// - /// + /// �������� /// public string Attach { get; set; } = string.Empty; /// - /// ֧ʱ + /// ֧�����ʱ�� /// public string TimeEnd { get; set; } = string.Empty; } @@ -275,78 +275,78 @@ public class WechatNotifyData #region Payment Record Models /// -/// ֧¼DTO +/// ֧����¼DTO /// public class PaymentRecordDto { /// - /// ¼ID + /// ��¼ID /// public long Id { get; set; } /// - /// ûID + /// �û�ID /// public long UserId { get; set; } /// - /// + /// ������ /// public string OrderNum { get; set; } = string.Empty; /// - /// ֧ + /// ֧����� /// public string ChangeMoney { get; set; } = "0.00"; /// - /// ֧˵ + /// ֧��˵�� /// public string Content { get; set; } = string.Empty; /// - /// ֧ͣ1=΢֧2=֧3=֧4=ȯ֧ + /// ֧�����ͣ�1=΢��֧����2=���֧����3=����֧����4=����ȯ֧�� /// public int PayType { get; set; } /// - /// ֧ı + /// ֧�������ı� /// public string PayTypeText { get; set; } = string.Empty; /// - /// ʱ + /// ����ʱ��� /// public long CreatedAt { get; set; } } /// -/// ֧¼ڲʹã +/// ����֧����¼�����ڲ�ʹ�ã� /// public class CreatePaymentRecordRequest { /// - /// ûID + /// �û�ID /// public long UserId { get; set; } /// - /// + /// ������ /// public string OrderNum { get; set; } = string.Empty; /// - /// ֧ + /// ֧����� /// public decimal Amount { get; set; } /// - /// ֧ + /// ֧������ /// public int PayType { get; set; } /// - /// ֧˵ + /// ֧��˵�� /// public string Content { get; set; } = string.Empty; } @@ -356,48 +356,48 @@ public class CreatePaymentRecordRequest #region Asset Deduction Models /// -/// ʲۼڲʹã +/// �ʲ��ۼ������ڲ�ʹ�ã� /// public class AssetDeductionRequest { /// - /// ûID + /// �û�ID /// public long UserId { get; set; } /// - /// ۼ + /// �ۼ���� /// public decimal Amount { get; set; } /// - /// ۼ˵ + /// �ۼ�˵�� /// public string Content { get; set; } = string.Empty; /// - /// + /// ���������� /// public string? OrderNum { get; set; } } /// -/// ʲۼڲʹã +/// �ʲ��ۼ�������ڲ�ʹ�ã� /// public class AssetDeductionResult { /// - /// Ƿɹ + /// �Ƿ�ɹ� /// public bool Success { get; set; } /// - /// Ϣ + /// ��Ϣ /// public string Message { get; set; } = string.Empty; /// - /// ۼ + /// �ۼ������ /// public decimal RemainingBalance { get; set; } } @@ -407,167 +407,177 @@ public class AssetDeductionResult #region Wechat Pay Configuration /// -/// ΢֧̻ãڲʹã +/// ΢��֧���̻����ã��ڲ�ʹ�ã� /// public class WechatPayMerchantConfig { /// - /// ̻ + /// �̻����� /// public string Name { get; set; } = string.Empty; /// - /// ̻ID + /// �̻�ID /// public string MchId { get; set; } = string.Empty; /// - /// ӦID + /// Ӧ��ID /// public string AppId { get; set; } = string.Empty; /// - /// ̻ԿV2汾ʹã + /// �̻���Կ��V2�汾ʹ�ã� /// public string Key { get; set; } = string.Empty; /// - /// ǰ׺ƥ̻3λַ + /// ����ǰ׺������ƥ���̻���3λ�ַ��� /// public string OrderPrefix { get; set; } = string.Empty; /// - /// Ȩأڸؾ⣩ + /// Ȩ�أ����ڸ��ؾ��⣩ /// public int Weight { get; set; } = 1; /// - /// ص֪ͨURL + /// �ص�֪ͨURL /// public string NotifyUrl { get; set; } = string.Empty; - // ===== V3 ֶ ===== + // ===== V3 �����ֶ� ===== /// - /// ֧汾: "V2" "V3"Ĭ "V2" + /// ֧���汾: "V2" �� "V3"��Ĭ�� "V2" /// public string PayVersion { get; set; } = "V2"; /// - /// APIv3 Կ32λַV3汾ʹã + /// APIv3 ��Կ��32λ�ַ�����V3�汾ʹ�ã� /// public string? ApiV3Key { get; set; } /// - /// ̻API֤кţV3汾ʹã + /// �̻�API֤�����кţ�V3�汾ʹ�ã� /// public string? CertSerialNo { get; set; } /// - /// ̻˽Կļ·V3汾ʹã + /// �̻�˽Կ�ļ�·����V3�汾ʹ�ã� /// public string? PrivateKeyPath { get; set; } /// - /// ΢֧ԿIDV3汾ʹã + /// 商户私钥PEM内容(V3版本使用,优先级高于 PrivateKeyPath) + /// + public string? PrivateKeyContent { get; set; } + + /// + /// ΢��֧����ԿID��V3�汾ʹ�ã� /// public string? WechatPublicKeyId { get; set; } /// - /// ΢֧Կļ·V3汾ʹã + /// ΢��֧����Կ�ļ�·����V3�汾ʹ�ã� /// public string? WechatPublicKeyPath { get; set; } + + /// + /// 微信支付公钥PEM内容(V3版本使用,优先级高于 WechatPublicKeyPath) + /// + public string? WechatPublicKeyContent { get; set; } } /// -/// Сãڲʹã +/// С�������ã��ڲ�ʹ�ã� /// public class MiniprogramConfig { /// - /// С + /// С�������� /// public string Name { get; set; } = string.Empty; /// - /// СAppId + /// С����AppId /// public string AppId { get; set; } = string.Empty; /// - /// СAppSecret + /// С����AppSecret /// public string AppSecret { get; set; } = string.Empty; /// - /// ǰ׺2λַ + /// ����ǰ׺��2λ�ַ��� /// public string OrderPrefix { get; set; } = string.Empty; /// - /// ̻IDб + /// �������̻�ID�б� /// public List Merchants { get; set; } = new(); /// - /// бŷָ + /// �����������б������ŷָ��� /// public string Domain { get; set; } = string.Empty; /// - /// ǷΪĬС + /// �Ƿ�ΪĬ��С���� /// public bool IsDefault { get; set; } } /// -/// ΢֧ãڲʹã +/// ΢��֧�����ã��ڲ�ʹ�ã� /// public class WechatPaySettings { /// - /// Ĭ̻ + /// Ĭ���̻����� /// public WechatPayMerchantConfig DefaultMerchant { get; set; } = new(); /// - /// ̻б + /// ���̻������б� /// public List Merchants { get; set; } = new(); /// - /// Сб + /// С���������б� /// public List Miniprograms { get; set; } = new(); /// - /// ͳһµAPIַ + /// ͳһ�µ�API��ַ /// public string UnifiedOrderUrl { get; set; } = "https://api.mch.weixin.qq.com/pay/unifiedorder"; /// - /// ֪ͨAPIַ + /// ����֪ͨAPI��ַ /// public string ShippingNotifyUrl { get; set; } = "https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info"; /// - /// Ĭϻص֪ͨURLַ + /// Ĭ�ϻص�֪ͨURL������ַ /// public string NotifyBaseUrl { get; set; } = string.Empty; } /// -/// ǰ׺Ϣڲʹã +/// ����ǰ׺��Ϣ���ڲ�ʹ�ã� /// public class OrderPrefixInfo { /// - /// ̻ǰ׺3λַ + /// �̻�ǰ׺��3λ�ַ��� /// public string? MerchantPrefix { get; set; } /// - /// Сǰ׺2λַ + /// С����ǰ׺��2λ�ַ��� /// public string? MiniprogramPrefix { get; set; } } @@ -577,124 +587,124 @@ public class OrderPrefixInfo #region Order Shipping Notify Models /// -/// ֪ͨڲʹã +/// ��������֪ͨ�����ڲ�ʹ�ã� /// public class OrderShippingNotifyRequest { /// - /// + /// ������ /// public string OrderNo { get; set; } = string.Empty; /// - /// ûOpenId + /// �û�OpenId /// public string OpenId { get; set; } = string.Empty; /// - /// ˾ + /// ������˾���� /// public string? LogisticsCompany { get; set; } /// - /// + /// �������� /// public string? TrackingNo { get; set; } /// - /// ƷѡĬϸݶԶɣ + /// ��Ʒ��������ѡ��Ĭ�ϸ��ݶ��������Զ����ɣ� /// public string? ItemDesc { get; set; } /// - /// ͣ1=ʵ2=ͬͣ3=Ʒ4=û + /// �������ͣ�1=ʵ��������2=ͬ�����ͣ�3=������Ʒ��4=�û����� /// public int LogisticsType { get; set; } = 4; /// - /// ģʽ1=ͳһ2=ֲ𷢻 + /// ����ģʽ��1=ͳһ������2=�ֲ𷢻� /// public int DeliveryMode { get; set; } = 1; } /// -/// ֪ͨڲʹã +/// ��������֪ͨ������ڲ�ʹ�ã� /// public class OrderShippingNotifyResult { /// - /// Ƿɹ + /// �Ƿ�ɹ� /// public bool Success { get; set; } /// - /// + /// ������ /// public int ErrCode { get; set; } /// - /// Ϣ + /// ������Ϣ /// public string ErrMsg { get; set; } = string.Empty; /// - /// ǷѴԶ + /// �Ƿ��Ѵ������Զ��� /// public bool QueuedForRetry { get; set; } } /// -/// ʧܶݣ洢Redisԣ +/// ����ʧ�ܶ������ݣ��洢��Redis���������ԣ� /// public class FailedShippingOrderData { /// - /// ûOpenId + /// �û�OpenId /// public string OpenId { get; set; } = string.Empty; /// - /// ӦID + /// Ӧ��ID /// public string AppId { get; set; } = string.Empty; /// - /// + /// ������ /// public string OrderNo { get; set; } = string.Empty; /// - /// ̻ + /// �̻��� /// public string MchId { get; set; } = string.Empty; /// - /// Ʒ + /// ��Ʒ���� /// public string ItemDesc { get; set; } = string.Empty; /// - /// + /// ������ /// public int ErrorCode { get; set; } /// - /// Ϣ + /// ������Ϣ /// public string ErrorMsg { get; set; } = string.Empty; /// - /// Դ + /// ���Դ��� /// public int RetryCount { get; set; } /// - /// ʱ䣨Unixʱ + /// �������ʱ�䣨Unixʱ����� /// public long LastRetryTime { get; set; } /// - /// ʱ䣨Unixʱ + /// ����ʱ�䣨Unixʱ����� /// public long CreateTime { get; set; } } @@ -704,83 +714,83 @@ public class FailedShippingOrderData #region Payment Type Enum /// -/// ֧ö +/// ֧������ö�� /// public enum PaymentType { /// - /// ΢֧ + /// ΢��֧�� /// WechatPay = 1, /// - /// ֧ + /// ���֧�� /// BalancePay = 2, /// - /// ֧ + /// ����֧�� /// IntegralPay = 3, /// - /// ȯ֧ + /// ����ȯ֧�� /// Money2Pay = 4 } /// -/// ö٣attachֵ +/// ��������ö�٣�attachֵ�� /// public static class OrderAttachType { /// - /// ֵ + /// ����ֵ /// public const string UserRecharge = "user_recharge"; /// - /// һͶ + /// һ���Ͷ��� /// public const string OrderYfs = "order_yfs"; /// - /// ̨Ͷ + /// ��̨�Ͷ��� /// public const string OrderLts = "order_lts"; /// - /// תתͶ + /// תת�Ͷ��� /// public const string OrderZzs = "order_zzs"; /// - /// ݶ + /// �����ݶ��� /// public const string OrderFlw = "order_flw"; /// - /// ̳Ͷ + /// �̳��Ͷ��� /// public const string OrderScs = "order_scs"; /// - /// Ͷ + /// �����Ͷ��� /// public const string OrderWxs = "order_wxs"; /// - /// Ͷ + /// �����Ͷ��� /// public const string OrderFbs = "order_fbs"; /// - /// 鿨 + /// �鿨������ /// public const string OrderCkj = "order_ckj"; /// - /// ˷ + /// �����˷� /// public const string OrderListSend = "order_list_send"; } @@ -791,149 +801,149 @@ public static class OrderAttachType #region Recharge Models /// -/// ֵ +/// ��ֵ���� /// public class RechargeRequest { /// - /// ֵ + /// ��ֵ��� /// public decimal Money { get; set; } } /// -/// ֵ΢֧Эأضֶ +/// ��ֵ�����΢��֧��Э����أ������ض��ֶ����� /// public class RechargeResult { /// - /// ״̬1=ɹ0=ʧ + /// ״̬��1=�ɹ���0=ʧ�� /// public int Status { get; set; } /// - /// Ϣ + /// ��Ϣ /// public string Msg { get; set; } = string.Empty; /// - /// ֧ + /// ֧������ /// public WechatPayData? Data { get; set; } /// - /// + /// ������ /// public string? OrderNum { get; set; } } /// -/// ֵӦ +/// ��ֵ������Ӧ /// public class RechargeConfigResponse { /// - /// ͳֵ + /// ��ͳ�ֵ��� /// public decimal MinMoney { get; set; } /// - /// ֵ˵ + /// ��ֵ˵�� /// public string Description { get; set; } = string.Empty; /// - /// ֵѡб + /// ��ֵѡ���б� /// public List Options { get; set; } = new(); } /// -/// ֵѡ +/// ��ֵѡ�� /// public class RechargeOption { /// - /// ֵ + /// ��ֵ��� /// public decimal Money { get; set; } /// - /// ͽ + /// ���ͽ�� /// public decimal Gift { get; set; } /// - /// ʾǩ + /// ��ʾ��ǩ /// public string Label { get; set; } = string.Empty; } /// -/// ֧״̬Ӧ +/// ֧��״̬��Ӧ /// public class PayStatusResponse { /// - /// ״̬0=֧1=֧2=ʧЧ + /// ״̬��0=��֧����1=��֧����2=��ʧЧ /// public int Status { get; set; } /// - /// ״̬ı + /// ״̬�ı� /// public string StatusText { get; set; } = string.Empty; /// - /// + /// ������ /// public string OrderNum { get; set; } = string.Empty; } /// -/// ֧ +/// ���֧������ /// public class BalancePayRequest { /// - /// + /// ������ /// public string OrderNum { get; set; } = string.Empty; /// - /// ֧ + /// ֧����� /// public decimal Amount { get; set; } } /// -/// ֧ +/// ���֧����� /// public class BalancePayResult { /// - /// ״̬1=ɹ0=ʧ + /// ״̬��1=�ɹ���0=ʧ�� /// public int Status { get; set; } /// - /// Ϣ + /// ��Ϣ /// public string Msg { get; set; } = string.Empty; /// - /// ʣ + /// ʣ����� /// public decimal Balance { get; set; } } /// -/// ֵ +/// ������ֵ�������� /// public class CreateRechargeOrderRequest { /// - /// ֵ + /// ��ֵ��� /// public decimal Money { get; set; } }