添加支付中心

This commit is contained in:
zpc 2024-11-26 09:06:35 +08:00
parent f2ad570efe
commit 565c5e0e26
15 changed files with 704 additions and 16 deletions

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Code\CloudGaming.Code\CloudGaming.Code.csproj" />
<ProjectReference Include="..\..\Model\CloudGaming.DtoModel\CloudGaming.DtoModel.csproj" />
<ProjectReference Include="..\..\Model\CloudGaming.GameModel\CloudGaming.GameModel.csproj" />
<ProjectReference Include="..\..\Model\CloudGaming.Model\CloudGaming.Model.csproj" />
<ProjectReference Include="..\..\Utile\HuanMeng.DotNetCore\HuanMeng.DotNetCore.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
@CloudGaming.PayApi_HostAddress = http://localhost:5229
GET {{CloudGaming.PayApi_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@ -0,0 +1,136 @@
using CloudGaming.Code.Account;
using CloudGaming.Code.AppExtend;
using CloudGaming.Code.DataAccess;
using CloudGaming.Code.Payment;
using CloudGaming.DtoModel.Account.User;
using CloudGaming.DtoModel.Payment;
using CloudGaming.Model.DbSqlServer.Db_User;
using HuanMeng.DotNetCore.MultiTenant.Contract;
using HuanMeng.DotNetCore.Redis;
using HuanMeng.DotNetCore.Utility;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System.Text;
namespace CloudGaming.PayApi.Controllers
{
/// <summary>
/// 支付中心
/// </summary>
/// <param name="logger"></param>
/// <param name="httpContextAccessor"></param>
/// <param name="serviceProvider"></param>
[Route("api/[controller]")]
[ApiController]
public class PayController(ILogger<PayController> logger, IHttpContextAccessor httpContextAccessor, IServiceProvider serviceProvider) : ControllerBase
{
/// <summary>
/// 支付中心回调
/// </summary>
/// <param name="tenant"></param>
/// <param name="pay"></param>
/// <param name="orderId"></param>
/// <param name="sign"></param>
/// <returns></returns>
[HttpPost("{tenant?}/{pay?}/{orderId?}/{sign?}")]
public async Task<string> Post(string? tenant, string? pay, string? orderId, string? sign)
{
var context = httpContextAccessor.HttpContext;
context.Request.EnableBuffering(); // Enable buffering to allow the body to be read multiple times
using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, leaveOpen: true))
{
var bodyContent = await reader.ReadToEndAsync();
logger.LogInformation($"请求支付回调接口,请求路径: {context.Request.Path}, 请求Body: {bodyContent}");
context.Request.Body.Position = 0;
}
#region
var orderInfo = PaymentExtend.ParseCustomString(orderId);
string newSign = $"{tenant}{orderId}{orderInfo.UserId}";
newSign = MD5Encryption.ComputeMD5Hash(newSign);
//签名不对
if (newSign != sign)
{
logger.LogError($"{orderId}订单支付签名不对==>{newSign}==>{context.Request.Path}");
return "error;签名不对";
}
#endregion
var appConfig = AppConfigurationExtend.GetAppConfigIdentifier(tenant);
if (appConfig == null)
{
return "error;租户不存在";
}
//重复请求锁
var baseKey = $"pay:lock:{orderId}";
var redis = appConfig.GetRedisDataBase();
if (!redis.StringSetLock(baseKey, "", 10))
{
return "success";
}
DAO dao = new DAO(serviceProvider, appConfig);
var intentOrder = await dao.DaoUser.Context.T_User_IntentOrder.FirstOrDefaultAsync(it => it.OrderId == orderId);
if (intentOrder == null)
{
redis.KeyDelete(baseKey);
return "error;订单不存在";
}
if (intentOrder.Status != (int)OrderState.)
{
redis.KeyDelete(baseKey);
return $"success";
}
intentOrder.Status = (int)OrderState.;
await dao.DaoUser.Context.SaveChangesAsync();
var product = await dao.DaoPhone.Context.T_Products.Where(it => it.ProductId == intentOrder.ProductId).FirstOrDefaultAsync();
if (product == null)
{
intentOrder.Status = (int)OrderState.;
await dao.DaoUser.Context.SaveChangesAsync();
return $"error;订单不存在";
}
var user = await dao.DaoUser.Context.T_User.FirstOrDefaultAsync(it => it.Id == intentOrder.UserId);
if (user == null)
{
intentOrder.Status = (int)OrderState.;
await dao.DaoUser.Context.SaveChangesAsync();
return $"error;用户不存在";
}
using (IDbContextTransaction transaction = dao.DaoUser.Context.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
try
{
T_User_OrderItems orderItems = new T_User_OrderItems();
orderItems.PayUrl = context.Request.Path;
//orderItems.
await product.OrderRewardsNoWorkAsync(user, pay, orderId, intentOrder.Price, intentOrder.IntentAt, dao, orderItems);
//intentOrder = await dao.daoDbMiaoYu.context.T_User_IntentOrder.FirstOrDefaultAsync(it => it.OrderId == orderId);
intentOrder.Status = (int)OrderState.;
await dao.DaoUser.Context.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception ex)
{
logger.LogError($"请求支付回调接口,发货失败,请求路径: {context.Request.Path}", ex);
await transaction.RollbackAsync();
intentOrder.Status = (int)OrderState.;
await dao.DaoUser.Context.SaveChangesAsync();
redis.KeyDelete(baseKey);
return $"error;出现异常{ex.Message}";
}
}
redis.KeyDelete(baseKey);
var userDiamond = await dao.DaoUser.Context.T_User_Currency.Where(it => it.UserId == user.Id && it.CurrencyType == (int)UserCurrencyType.).FirstOrDefaultAsync();
//刷新钻石缓存
await AccountExtend.RefreshUserInfo(user.Id, redis, (int)(userDiamond?.CurrencyMoney ?? 0), intentOrder.Price > 0 ? true : false);
return $"success";
}
}
}

View File

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
namespace CloudGaming.PayApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

View File

@ -0,0 +1,29 @@
# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。
# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER $APP_UID
WORKDIR /app
EXPOSE 80
# 此阶段用于生成服务项目
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Api/CloudGaming.PayApi/CloudGaming.PayApi.csproj", "Api/CloudGaming.PayApi/"]
RUN dotnet restore "./Api/CloudGaming.PayApi/CloudGaming.PayApi.csproj"
COPY . .
WORKDIR "/src/Api/CloudGaming.PayApi"
RUN dotnet build "./CloudGaming.PayApi.csproj" -c $BUILD_CONFIGURATION -o /app/build
# 此阶段用于发布要复制到最终阶段的服务项目
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./CloudGaming.PayApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "CloudGaming.PayApi.dll"]

View File

@ -0,0 +1,139 @@
using CloudGaming.Code.AppExtend;
using CloudGaming.Code.DataAccess.MultiTenantUtil;
using CloudGaming.Code.Filter;
using HuanMeng.DotNetCore.MiddlewareExtend;
using HuanMeng.DotNetCore.SwaggerUtile;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
using Serilog;
using System.Diagnostics;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
#region
// Add services to the container.
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext());
builder.Services.AddSingleton(typeof(ILogger<CloudGamingBase>), serviceProvider =>
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
return loggerFactory.CreateLogger<CloudGamingBase>();
});
//
builder.Services.AddSingleton(typeof(ILogger<ExceptionMiddleware>), serviceProvider =>
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
return loggerFactory.CreateLogger<ExceptionMiddleware>();
});
#endregion
builder.Services.AddHttpContextAccessor(); //添加httpContext注入访问
#region
//builder.Services.AddControllers();
builder.Services.AddControllers(options =>
{
})
.AddNewtonsoftJson(options =>
{
// 配置 Newtonsoft.Json 选项
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; // 忽略循环引用
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();// 首字母小写(驼峰样式)
//options.SerializerSettings.ContractResolver = new LanguageContractResolver(builder.Services);
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";// 时间格式化
options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.None;
});
//CustomResultFilter
//builder.Services.AddSingleton<ObjectResultExecutor, CustomObjectResultExecutor>();
#endregion
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
string description = "";
var filePath = Path.GetFullPath(".versionDescribe");
if (File.Exists(filePath))
{
description = File.ReadAllText(filePath);
}
c.SwaggerDoc("v1", new OpenApiInfo { Title = "蒸汽云游戏支付", Version = "0.0.1", Description = description });
foreach (var assemblies in AppDomain.CurrentDomain.GetAssemblies())
{
// 添加 XML 注释文件路径
var xmlFile = $"{assemblies.GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
if (File.Exists(xmlPath))
{
c.IncludeXmlComments(xmlPath);
}
}
c.ParameterFilter<LowercaseParameterFilter>();
c.RequestBodyFilter<LowercaseRequestFilter>();
});
builder.AddAppConfigClient();
var app = builder.Build();
// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.EnableDeepLinking();
c.DefaultModelsExpandDepth(3);
c.DefaultModelExpandDepth(3);
c.EnableFilter("true");
//c.RoutePrefix = string.Empty;
c.SwaggerEndpoint("/swagger/v1/swagger.json", "蒸汽云游戏支付 API V1");
// 使用自定义CSS
c.InjectStylesheet("/custom.css");
});
//}
app.UseAuthorization();
//数据库中间件
app.UseMultiTenant();
app.MapControllers();
app.UseMiddlewareAll();
#region
app.MapGet("/", () => "请求成功").WithName("默认请求");
var startDateTime = DateTime.Now;
var InformationalVersion = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
Console.WriteLine($"version:{InformationalVersion}");
app.MapGet("/system", () =>
{
using Process currentProcess = Process.GetCurrentProcess();
// CPU使用率 (一般是一个0-100之间的值但实际是时间占比需要转换)
double cpuUsage = currentProcess.TotalProcessorTime.TotalMilliseconds / Environment.TickCount * 100;
// 已用内存 (字节)
long memoryUsage = currentProcess.WorkingSet64;
return new
{
msg = $"系统信息:启动时间:{startDateTime.ToString("yyyy-MM-dd HH:mm:ss")},已安全运行时间:{DateTime.Now.Subtract(startDateTime).TotalMinutes.ToString("0.##")}分钟",
startDateTime,
MemoryUsage = $"{memoryUsage / (1024.0 * 1024.0):F2}MB",
CPUUsage = $"{cpuUsage:F2}%"
};
}).WithName("获取系统数据");
#endregion
app.Run();

View File

@ -0,0 +1,41 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5229"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true,
"useSSL": false
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:40520",
"sslPort": 0
}
}
}

View File

@ -0,0 +1,13 @@
namespace CloudGaming.PayApi
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@ -0,0 +1,26 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AgileConfig": {
"appId": "CloudGaming",
"secret": "95BB717C61D1ECB0E9FB82C932CC77FF",
"nodes": "http://124.220.55.158:94", //使
"url": "http://124.220.55.158:94",
"env": "DEV",
"name": "payClient",
"UserName": "admin",
"Password": "dbt@com@1234"
},
//
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://*:802"
}
}
}
}

View File

@ -0,0 +1,71 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "../output/paylogs/info/log-.txt",
"rollingInterval": "Day",
"restrictedToMinimumLevel": "Information", //
"shared": true
//"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "../output/paylogs/error/log-.txt",
"rollingInterval": "Day", //
"restrictedToMinimumLevel": "Error", // // VerboseDebugInformationWarningError Fatal
"shared": true //
// "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "../output/paylogs/debug/log-.txt",
"rollingInterval": "Day", //
"restrictedToMinimumLevel": "Debug", // // VerboseDebugInformationWarningError Fatal
"shared": true //
// "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
},
"AgileConfig": {
"appId": "CloudGaming",
"secret": "95BB717C61D1ECB0E9FB82C932CC77FF",
"nodes": "http://124.220.55.158:94", //使
"url": "http://124.220.55.158:94",
"env": "TEST",
"name": "payClient",
"UserName": "admin",
"Password": "dbt@com@1234"
},
//
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://*:80"
}
}
}
}

View File

@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# 17
# Visual Studio Version 17
VisualStudioVersion = 17.10.35027.167
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1-core", "1-core", "{FCA3CA4B-1993-429A-B2E9-2B05DB44F10E}"
@ -36,6 +36,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudGaming.DtoModel", "Mod
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudGaming.Test", "Console\CloudGaming.Test\CloudGaming.Test.csproj", "{830841B9-E013-4FD5-8D31-D85545870C1C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudGaming.PayApi", "Api\CloudGaming.PayApi\CloudGaming.PayApi.csproj", "{452D87B5-A7E0-4EBD-9CF2-1AFF5941065B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -74,6 +76,10 @@ Global
{830841B9-E013-4FD5-8D31-D85545870C1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{830841B9-E013-4FD5-8D31-D85545870C1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{830841B9-E013-4FD5-8D31-D85545870C1C}.Release|Any CPU.Build.0 = Release|Any CPU
{452D87B5-A7E0-4EBD-9CF2-1AFF5941065B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{452D87B5-A7E0-4EBD-9CF2-1AFF5941065B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{452D87B5-A7E0-4EBD-9CF2-1AFF5941065B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{452D87B5-A7E0-4EBD-9CF2-1AFF5941065B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -87,6 +93,7 @@ Global
{1120C146-6B83-4E4E-8A39-BD09466C7E1B} = {A3F00FB0-49D6-48B1-99D9-4619634DF8D9}
{96CD0865-0AD5-41B3-89A2-374FF17CDD16} = {A3F00FB0-49D6-48B1-99D9-4619634DF8D9}
{830841B9-E013-4FD5-8D31-D85545870C1C} = {9F7EF36C-17BB-4F93-927E-F462FE3C9337}
{452D87B5-A7E0-4EBD-9CF2-1AFF5941065B} = {51CB40D2-99F5-43E8-95B4-3A75C91736A6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1D299D92-FA27-47A0-8D78-43D1FAFE7628}

View File

@ -3,6 +3,7 @@ using Bogus.DataSets;
using CloudGaming.Code.Account.Contract;
using CloudGaming.Code.Account.Login;
using CloudGaming.Code.Account.UserCurrency;
using CloudGaming.Code.AppExtend;
using CloudGaming.Code.DataAccess;
using CloudGaming.Code.Other;
using CloudGaming.DtoModel.Account.Login;
@ -103,6 +104,27 @@ namespace CloudGaming.Code.Account
userInfoCache = await GetUserInfo(userId, cloudGamingBase) ?? new UserInfoCache();
return userInfoCache;
}
/// <summary>
/// 刷新用户钻石,和是否支付缓存
/// </summary>
/// <param name="userId"></param>
/// <param name="database"></param>
/// <param name="diamond"></param>
/// <param name="isPay"></param>
/// <returns></returns>
public static async Task RefreshUserInfo(int userId, IDatabase database, int diamond, bool isPay)
{
string key = GetUserInfoRedisKey(userId);
var userInfo = await database.StringGetAsync<UserInfoCache>(key);
if (userInfo != null)
{
userInfo.Diamond = diamond;
userInfo.IsPay = isPay;
await database.StringSetAsync(key, userInfo, TimeSpan.FromMinutes(30));
}
}
/// <summary>
/// 获取用户信息
/// </summary>
@ -241,7 +263,7 @@ namespace CloudGaming.Code.Account
return userInfo;
}
/// <summary>
/// 发送消息
@ -274,7 +296,7 @@ namespace CloudGaming.Code.Account
}
/// <summary>
/// 获取用户购买过的产品
/// </summary>

View File

@ -80,20 +80,16 @@ namespace CloudGaming.Code.Account
/// <param name="title"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static bool ConsumeMoneyNoWork(this T_User user, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null, string orderId = "", string title = "")
public static async Task<bool> ConsumeMoneyNoWork(this T_User user, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null, string orderId = "", string title = "")
{
if (user == null || user.Id == 0)
{
throw new ArgumentNullException("用户不能为空");
}
int userId = user.Id;
return ConsumeMoneyNoWork(userId, userCurrencyType, money, dao, orderId: orderId, title: title);
}
public static bool ConsumeMoneyNoWork(int userId, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null, string remarks = "", string title = "", string orderId = "")
{
return true;
return await UserConsumeDiamondMoneyAsync(dao, userId, userCurrencyType, money, title, orderId, _currency);
}
/// <summary>
/// 扣除当前用户钻石
@ -135,7 +131,40 @@ namespace CloudGaming.Code.Account
public static async Task<bool> UserConsumeDiamondMoneyAsync(this CloudGamingBase cloudGamingBase, decimal money, Action<T_User_DiamondList>? userDoamondAction = null)
{
T_User_Currency currency = new T_User_Currency();
var userConsumeMoney = new DiamondConsumeMoney(cloudGamingBase.Dao, cloudGamingBase.UserInfo.UserId, UserCurrencyType., currency);
try
{
var isSuccess = await UserConsumeDiamondMoneyAsync(cloudGamingBase.Dao, cloudGamingBase.UserInfo.UserId, money, userDoamondAction, currency);//
if (!isSuccess)
{
return false;
}
cloudGamingBase.UserInfo.Diamond = (int)currency.CurrencyMoney;
await cloudGamingBase.SaveUserInfoCacheChangesAsync();
}
catch (Exception ex)
{
return false;
}
return true;
}
/// <summary>
/// 扣除或者添加当前用户钻石
/// </summary>
/// <param name="dao"></param>
/// <param name="userId"></param>
/// <param name="money">负数扣除,正数添加</param>
/// <param name="userDoamondAction"></param>
/// <returns></returns>
public static async Task<bool> UserConsumeDiamondMoneyAsync(DAO dao, int userId, decimal money, Action<T_User_DiamondList>? userDoamondAction = null, T_User_Currency userCurrency = null)
{
var userConsumeMoney = new DiamondConsumeMoney(dao, userId, UserCurrencyType., userCurrency);
try
{
var isSuccess = await userConsumeMoney.ConsumeMoneyAsync(money);
@ -143,8 +172,6 @@ namespace CloudGaming.Code.Account
{
return false;
}
cloudGamingBase.UserInfo.Diamond = (int)currency.CurrencyMoney;
await cloudGamingBase.SaveUserInfoCacheChangesAsync();
UserCurrencyConsumeType consumeType = money >= 0 ? UserCurrencyConsumeType. : UserCurrencyConsumeType.;
T_User_DiamondList userDiamondList = new T_User_DiamondList()
{
@ -155,14 +182,14 @@ namespace CloudGaming.Code.Account
OrderCode = "",
Title = "",
UpdateAt = DateTime.Now,
UserId = cloudGamingBase.UserInfo.UserId,
UserId = userId,
};
if (userDoamondAction != null)
{
userDoamondAction(userDiamondList);
}
await cloudGamingBase.Dao.DaoUser.Context.AddAsync(userDiamondList);
await cloudGamingBase.Dao.DaoUser.Context.SaveChangesAsync();
await dao.DaoUser.Context.AddAsync(userDiamondList);
await dao.DaoUser.Context.SaveChangesAsync();
}
catch (Exception ex)
{
@ -203,6 +230,26 @@ namespace CloudGaming.Code.Account
}
return await UserConsumeDiamondMoneyAsync(cloudGamingBase, money, it => { it.Title = title; it.OrderCode = orderId; });
}
/// <summary>
/// 充值或者消耗用户货币
/// </summary>
/// <param name="dao"></param>
/// <param name="userId"></param>
/// <param name="userCurrencyType"></param>
/// <param name="money"></param>
/// <param name="title"></param>
/// <param name="orderId"></param>
/// <returns></returns>
public static async Task<bool> UserConsumeDiamondMoneyAsync(DAO dao, int userId, UserCurrencyType userCurrencyType, decimal money, string title = "", string orderId = "", T_User_Currency currency = null)
{
if (userCurrencyType == UserCurrencyType.)
{
return await UserConsumeDiamondMoneyAsync(dao, userId, money, it => { it.Title = title; it.OrderCode = orderId; }, currency);
}
return await UserConsumeDiamondMoneyAsync(dao, userId, money, it => { it.Title = title; it.OrderCode = orderId; }, currency);
}
/// <summary>
/// 用户玩游戏消耗钻石
/// </summary>

View File

@ -0,0 +1,88 @@
using CloudGaming.Code.Account;
using CloudGaming.Code.DataAccess;
using CloudGaming.DtoModel.Account.User;
using CloudGaming.DtoModel.Payment;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.Payment;
public static class OrderExtend
{
/// <summary>
/// 不带锁,出现异常需要自己处理
/// </summary>
/// <param name="product"></param>
/// <param name="user"></param>
/// <param name="pay"></param>
/// <param name="orderId"></param>
/// <param name="price"></param>
/// <param name="intentDate"></param>
/// <param name="dao"></param>
/// <returns></returns>
public static async Task OrderRewardsNoWorkAsync(this T_Products product, T_User user, string pay, string orderId, decimal price, DateTime intentDate, DAO dao, T_User_OrderItems orderItems = null)
{
var userId = user.Id;
var chargeMoneyCount = dao.DaoUser.Context.T_User_Order.Count(it => it.UserId == userId && it.ProductId == product.ProductId);
var productReward = await dao.DaoPhone.Context.T_Products_Reward.Where(it => it.ProductId == product.ProductId).ToListAsync();
if (productReward != null && productReward.Count > 0)
{
List<string> tips = new List<string>();
//List<T_User_Currency> user_Currencies = new List<T_User_Currency>();
foreach (var reward in productReward)
{
var money = reward.Money;
var currency = (UserCurrencyType)reward.CurrencyType;
var userCurrency = new T_User_Currency();
await user.ConsumeMoneyNoWork(currency, money, dao, userCurrency, orderId);
tips.Add($"获得{currency}*{money}");
if (product.IsFirstCharge && chargeMoneyCount == 0 && reward.FirstChargeMoney > 0)
{
await user.ConsumeMoneyNoWork(currency, reward.FirstChargeMoney ?? 0, dao, userCurrency, orderId, $"首充赠送{currency}{reward.FirstChargeMoney}");
tips.Add($"首充赠送{currency}*{money}");
}
}
var rewardTips = string.Join(',', tips.ToArray());
T_User_Order order = new T_User_Order()
{
OrderId = orderId,
CreatedAt = DateTime.Now,
OrderDate = intentDate,
PaymentDate = DateTime.Now,
PaymentDay = DateOnly.FromDateTime(DateTime.Now),
PaymentMethod = pay,
ProductId = product.ProductId,
Status = (int)OrderState.,
TenantId = product.TenantId,
TotalPrice = price,
UpdatedAt = DateTime.Now,
UserId = userId,
};
if (orderItems == null)
{
orderItems = new T_User_OrderItems();
}
orderItems.OrderId = orderId;
orderItems.RewardTips = rewardTips;
orderItems.Product = product.Id;
orderItems.TenantId = product.TenantId;
orderItems.ProductId = product.ProductId;
orderItems.RewardInfo = JsonConvert.SerializeObject(productReward);
orderItems.RewardTips = rewardTips;
dao.DaoUser.Context.T_User_OrderItems.Add(orderItems);
dao.DaoUser.Context.T_User_Order.Add(order);
await dao.DaoUser.Context.SaveChangesAsync();
}
}
}

View File

@ -49,6 +49,9 @@ namespace HuanMeng.DotNetCore.Redis
}
return database;
}
/// <summary>
///
/// </summary>