You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using GDZZ.Application.Entity;
using GDZZ.Core.Entity;
using GDZZ.Core;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Furion.EventBus;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Http;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using GDZZ.Application.Service.WXPay.Dto;
using TenPayOldV3 = Senparc.Weixin.TenPay.V3.TenPayV3;
using Senparc.Weixin;
using Senparc.Weixin.TenPay.V3;
using Senparc.Weixin.TenPay;
using Senparc.CO2NET.Utilities;
using Senparc.Weixin.Sample.CommonService.TemplateMessage;
using System.IO;
using System.Text;
using Senparc.Weixin.Exceptions;
using Microsoft.AspNetCore.Authorization;
using System.Collections.Generic;
using Mapster;
using Furion.FriendlyException;
namespace GDZZ.Application.Service.WXPay
{
[ApiDescriptionSettings("Application", Name = "WXPay", Order = 1)]
public class WXPayService : IWXPayService, IDynamicApiController, ITransient
{
private readonly SqlSugarRepository<BaseUser> Baseuser; // wx用户仓储
private readonly SqlSugarRepository<SysUser> _sysUserRep; // 用户表仓储
private readonly SqlSugarRepository<SysTenant> _sysTenantRep; //租户仓储
private readonly SqlSugarRepository<SeIF> self; //职业仓储
private readonly SqlSugarRepository<Consume> ComsumeRep; //消费记录仓储
private readonly SqlSugarRepository<Balance> balance; //余额仓储
private readonly SqlSugarRepository<MiniRecharge> rechargeRep; //充值仓储
private readonly SqlSugarRepository<MiniPayTake> payTakeRep; //支付仓储
private readonly WechatOAuth _wechatOAuth; //微信权限服务
private readonly IEventPublisher _eventPublisher; //事件写入服务
private readonly IHttpContextAccessor _httpContextAccessor; //http服务
/// <summary>
/// 获取配置文件
/// </summary>
private readonly SenparcWeixinSetting _oauthConfig;
public WXPayService(
IOptions<OAuthOptions> options,
SqlSugarRepository<BaseUser> Baseuser,
SqlSugarRepository<SysTenant> sysTenantRep,
SqlSugarRepository<SysUser> sysUserRep,
SqlSugarRepository<Balance> balance,
SqlSugarRepository<Consume> ComsumeRep,
SqlSugarRepository<SeIF> Self,
SqlSugarRepository<MiniRecharge> rechargeRep,
SqlSugarRepository<MiniPayTake> payTakeRep,
WechatOAuth wechatOAuth,
IHttpContextAccessor _httpContextAccessor,
IEventPublisher eventPublisher)
{
this.self = Self;
this.balance = balance;
this.Baseuser = Baseuser;
this.ComsumeRep = ComsumeRep;
this._sysUserRep = sysUserRep;
this._sysTenantRep = sysTenantRep;
this.rechargeRep = rechargeRep;
this.payTakeRep = payTakeRep;
this._wechatOAuth = wechatOAuth;
this._oauthConfig = options.Value.SenparcWeixin;
this._httpContextAccessor = _httpContextAccessor;
}
/// <summary>
/// 查询余额
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Mini/v1/GetUserBalance")]
public async Task<BalanceOut> GetUserBalance()
{
var balan = await this.balance.AsQueryable().Filter("TenantId", true).SingleAsync(x => x.UserID == UserManager.UserId);
if (balan == null)
return null;
return new BalanceOut()
{
Amount = balan.Amount,
UserID = UserManager.UserId,
};
}
/// <summary>
/// 充值记录查询
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Mini/v1/GetRechargeList")]
public async Task<List<RechargeOut>> GetRechargeList()
{
var rechargeLiist =await this.rechargeRep.Where(x => x.CreatedUserId == UserManager.UserId).ToListAsync();
return rechargeLiist.Adapt<List<RechargeOut>>();
}
/// <summary>
/// 修改余额
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Mini/v1/UpBalance")]
public async Task<dynamic> UpBalance(decimal Consume,long? ResumeID)
{
var comrep = await this.ComsumeRep.Where(x=>x.ResumeID== ResumeID).FirstAsync();
if(!comrep.IsNullOrZero()) //已经消费过了
return true;
var ban = await this.balance.Where(x => x.UserID == UserManager.UserId).FirstAsync();
if (ban == null)
throw Oops.Oh(ErrorCode.xg1002);
ban.Amount -= Consume;
if (ban.Amount < 0)
throw Oops.Oh(ErrorCode.B1001);
await this.ComsumeRep.InsertAsync(new Consume()
{
CAmount= Consume,
Surplus = ban.Amount,
ResumeID = ResumeID
});
return await this.balance.AsUpdateable(ban).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync()>0;
}
/// <summary>
/// 查询消费记录
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Mini/v1/GetBalance")]
public async Task<dynamic> GetBalance()
{
return await this.ComsumeRep.Where(x=>x.UserID == UserManager.UserId).ToListAsync();
}
/// <summary>
///微信小程序支付
/// </summary>
/// <param name="authUserInput">商品Id</param>
/// <returns></returns>
[HttpPost]
[Route("Mini/v1/wxpay")]
public async Task<dynamic> WxPay(AuthUserInput authUserInput)
{
var recharge = await this.rechargeRep.InsertReturnEntityAsync(new MiniRecharge()
{
PaymentMoney = authUserInput.Money,
Status = (int)RechargeEnum.NoFinis,
TotalPrice = authUserInput.Money
});
var payTake = await this.payTakeRep.InsertReturnEntityAsync(new MiniPayTake()
{
PaymentMoney = authUserInput.Money,
OrderId = recharge.Id,
PaySn = "",
PayStatus = (int)PayStatusEnum.NotPaying
});
int pMoney = (int)(authUserInput.Money * 100);
string sp_billno =
$"{Config.SenparcWeixinSetting.TenPayV3_MchId}{SystemTime.Now:yyyyMMddHHmmss}{TenPayV3Util.BuildRandomStr(6)}";
string timeStamp = TenPayV3Util.GetTimestamp();
string nonceStr = TenPayV3Util.GetNoncestr();
TenPayV3UnifiedorderRequestData xmlDataInfo = new TenPayV3UnifiedorderRequestData(Config.SenparcWeixinSetting.WxOpenAppId,
Config.SenparcWeixinSetting.TenPayV3_MchId,"余额充值", sp_billno,
pMoney,
"127.0.0.1",
Config.SenparcWeixinSetting.TenPayV3_TenpayNotify, TenPayV3Type.JSAPI, authUserInput.OpenID,
Config.SenparcWeixinSetting.TenPayV3_Key, nonceStr, null, null, null, null, payTake.OrderId.ToString());
Console.WriteLine(xmlDataInfo.PackageRequestHandler.ParseXML());
var result = TenPayOldV3.Unifiedorder(xmlDataInfo);//调用统一订单接口
string packageStr = "prepay_id=" + result.prepay_id;
return new
{
success = true,
result.prepay_id,
appId = Config.SenparcWeixinSetting.WxOpenAppId,
timeStamp,
nonceStr,
package = packageStr,
signType = "MD5",
paySign = TenPayV3.GetJsPaySign(Config.SenparcWeixinSetting.WxOpenAppId, timeStamp, nonceStr,
packageStr, Config.SenparcWeixinSetting.TenPayV3_Key)
};
}
/// <summary>
/// 微信小程序支付回调
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("/Mini/NotifyUrl")]
[UnifyResult(typeof(string))]
[AllowAnonymous]
public async Task<string> NotifyUrl()
{
try
{
ResponseHandler resHandler = new ResponseHandler(this._httpContextAccessor.HttpContext);
string return_code = resHandler.GetParameter("return_code");
string return_msg = resHandler.GetParameter("return_msg");
var res = "";
resHandler.SetKey(Config.SenparcWeixinSetting.TenPayV3_Key);
//验证请求是否从微信发过来(安全)
if (resHandler.IsTenpaySign() && return_code.ToUpper() == "SUCCESS")
{
res = "success";//正确的订单处理
//直到这里,才能认为交易真正成功了,可以进行数据库操作,但是别忘了返回规定格式的消息!
Console.WriteLine("回调成功");
//attach
var paymentId = long.Parse(resHandler.GetParameter("attach"));
//业务处理
var paytake = await this.payTakeRep.Where(x => x.OrderId == paymentId).SingleAsync();
if (!paytake.IsEmpty())
{
paytake.PayStatus = (int)PayStatusEnum.Paying;
this.payTakeRep.Update(paytake);
}
var recharge = await this.rechargeRep.Where(x => x.Id == paymentId).SingleAsync();
if (!recharge.IsEmpty())
{
recharge.Status = (int)RechargeEnum.Finish;
this.rechargeRep.Update(recharge);
var balan = await this.balance.AsQueryable().Filter("TenantId", true).Where(x => x.UserID == paytake.CreatedUserId).SingleAsync();
if (!balan.IsEmpty())
{
balan.Amount = recharge.PaymentMoney;
this.balance.Update(balan);
}
else
{
this.balance.Insert(new Balance()
{
Amount = recharge.PaymentMoney,
UserID = (long)paytake.CreatedUserId
});
}
}
}
else
{
Console.WriteLine("回调失败");
res = "wrong";//错误的订单处理
}
/* 这里可以进行订单处理的逻辑 */
//发送支付成功的模板消息
try
{
string appId = Config.SenparcWeixinSetting.TenPayV3_AppId;//与微信公众账号后台的AppId设置保持一致区分大小写。
string openId = resHandler.GetParameter("openid");
var templateData = new WeixinTemplate_PaySuccess("https://weixin.senparc.com", "微信支付 V2 购买商品", "状态:" + return_code);
Senparc.Weixin.WeixinTrace.SendCustomLog("支付成功模板消息参数", appId + " , " + openId);
var result = Senparc.Weixin.MP.AdvancedAPIs.TemplateApi.SendTemplateMessage(appId, openId, templateData);
}
catch (Exception ex)
{
Senparc.Weixin.WeixinTrace.SendCustomLog("支付成功模板消息", ex.ToString());
}
#region 记录日志
var logDir = ServerUtility.ContentRootMapPath(string.Format("~/App_Data/TenPayNotify/{0}", SystemTime.Now.ToString("yyyyMMdd")));
if (!Directory.Exists(logDir))
{
Directory.CreateDirectory(logDir);
}
var logPath = Path.Combine(logDir, string.Format("{0}-{1}-{2}.txt", SystemTime.Now.ToString("yyyyMMdd"), SystemTime.Now.ToString("HHmmss"), Guid.NewGuid().ToString("n").Substring(0, 8)));
using (var fileStream = System.IO.File.OpenWrite(logPath))
{
var notifyXml = resHandler.ParseXML();
fileStream.Write(Encoding.Default.GetBytes(notifyXml), 0, Encoding.Default.GetByteCount(notifyXml));
fileStream.Close();
}
#endregion
string xml = string.Format(@"<xml>
<return_code><![CDATA[{0}]]></return_code>
<return_msg><![CDATA[{1}]]></return_msg>
</xml>", return_code, return_msg);
return xml;
}
catch (Exception ex)
{
WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex));
throw;
}
}
}
}