完成订单发货

This commit is contained in:
zpc 2024-08-28 14:33:31 +08:00
parent 8dc9ee123c
commit e6fa2ea5f8
10 changed files with 410 additions and 31 deletions

View File

@ -60,6 +60,18 @@ namespace HuanMeng.MiaoYu.Code.AppExtend
return AppConfigs.FirstOrDefault().Value;
}
/// <summary>
/// 获取配置项
/// </summary>
/// <param name="identifier"></param>
/// <returns></returns>
public static AppConfig? GetAppConfigIdentifier(string identifier)
{
var app = AppConfigs.Where(it => it.Value.Identifier == identifier).Select(it => it.Value).FirstOrDefault();
return app;
}
/// <summary>
/// 配置版本号

View File

@ -1,3 +1,7 @@
using HuanMeng.MiaoYu.Code.AppExtend;
using Microsoft.IdentityModel.Tokens;
using StackExchange.Redis;
using System;
@ -38,6 +42,20 @@ namespace HuanMeng.MiaoYu.Code.Base
//database.StringSet("", "", TimeSpan.FromSeconds(10),when: When.NotExists);
return database;
}
/// <summary>
///
/// </summary>
/// <param name="appConfig"></param>
/// <returns></returns>
public static IDatabase GetRedis(AppConfig appConfig)
{
if (appConfig == null || string.IsNullOrEmpty(appConfig.RedisConnectionString))
{
throw new ArgumentNullException("AppConfig不能为空");
}
return GetRedis(appConfig.RedisConnectionString);
}
/// <summary>
///
/// </summary>

View File

@ -134,7 +134,7 @@ namespace HuanMeng.MiaoYu.Code.Payment
Notes = "",
ProductId = productCache.ProductId,
Quantity = 1,
Status = 0,
Status = (int)OrderState.,
UpdatedAt = DateTime.Now,
OrderId = orderId,
};

View File

@ -108,14 +108,14 @@ namespace HuanMeng.MiaoYu.Code.Users
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="Exception"></exception>
public static bool ConsumeMoneyNoWork(this T_User user, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null)
public static bool ConsumeMoneyNoWork(this T_User user, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null, string remarks = "")
{
if (user == null || user.Id == 0)
{
throw new ArgumentNullException("用户不能为空");
}
int userId = user.Id;
return ConsumeMoneyNoWork(userId, userCurrencyType, money, dao, _currency);
return ConsumeMoneyNoWork(userId, userCurrencyType, money, dao, _currency, remarks);
}
/// <summary>
/// 扣除或者充值货币
@ -128,14 +128,14 @@ namespace HuanMeng.MiaoYu.Code.Users
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="Exception"></exception>
public static bool ConsumeMoneyNoWork(this T_User_Data user, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null)
public static bool ConsumeMoneyNoWork(this T_User_Data user, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null, string remarks = "")
{
if (user == null || user.UserId == 0)
{
throw new ArgumentNullException("用户不能为空");
}
int userId = user.UserId;
return ConsumeMoneyNoWork(userId, userCurrencyType, money, dao, _currency);
return ConsumeMoneyNoWork(userId, userCurrencyType, money, dao, _currency, remarks);
}
@ -170,7 +170,7 @@ namespace HuanMeng.MiaoYu.Code.Users
/// <param name="dao">数据库</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static bool ConsumeMoneyNoWork(int userId, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null)
public static bool ConsumeMoneyNoWork(int userId, UserCurrencyType userCurrencyType, decimal money, DAO dao, T_User_Currency? _currency = null, string remarks = "")
{
var userCurrency = dao.daoDbMiaoYu.context.T_User_Currency.FirstOrDefault(it => it.UserId == userId && it.CurrencyType == (int)userCurrencyType);
if (userCurrency == null)
@ -204,7 +204,7 @@ namespace HuanMeng.MiaoYu.Code.Users
if (userCurrencyType == UserCurrencyType. && userCurrencyConsumeType == UserCurrencyConsumeType.)
{
var mintes = DateTime.Now.AddMinutes(-5);
log = dao.daoDbMiaoYu.context.T_User_Currency_Log.Where(it => it.CreateTime > mintes).OrderByDescending(it => it.CreateTime).FirstOrDefault();
log = dao.daoDbMiaoYu.context.T_User_Currency_Log.Where(it => it.CreateTime > mintes && it.ConsumeType == (int)UserCurrencyConsumeType. && it.CurrencyType == (int)userCurrencyType).OrderByDescending(it => it.CreateTime).FirstOrDefault();
}
var tempMoney = Math.Abs(money);
//消费
@ -219,7 +219,7 @@ namespace HuanMeng.MiaoYu.Code.Users
TenantId = dao.daoDbMiaoYu.context.TenantInfo.TenantId,
UpdateTime = DateTime.Now,
UserId = userId,
Remarks = ""
Remarks = remarks
};
dao.daoDbMiaoYu.context.T_User_Currency_Log.Add(log);
}

View File

@ -148,6 +148,16 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext
/// </summary>
public virtual DbSet<T_Model_Config> T_Model_Config { get; set; }
/// <summary>
/// 订单完成表
/// </summary>
public virtual DbSet<T_Order> T_Order { get; set; }
/// <summary>
/// 订单详情表
/// </summary>
public virtual DbSet<T_OrderItems> T_OrderItems { get; set; }
/// <summary>
/// 商城表
/// </summary>
@ -828,6 +838,70 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext
}
});
modelBuilder.Entity<T_Order>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Order__3214EC07C8DD7EE1");
entity.ToTable(tb => tb.HasComment("订单完成表"));
entity.Property(e => e.CreatedAt)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.OrderDate)
.HasComment("订单创建时间")
.HasColumnType("datetime");
entity.Property(e => e.OrderId)
.HasMaxLength(64)
.HasComment("订单编号");
entity.Property(e => e.PaymentDate)
.HasComment("订单支付时间")
.HasColumnType("datetime");
entity.Property(e => e.PaymentDay).HasComment("订单创建天");
entity.Property(e => e.PaymentMethod)
.HasMaxLength(10)
.HasComment("订单支付方式");
entity.Property(e => e.ProductId)
.HasMaxLength(100)
.HasComment("购买的产品Id");
entity.Property(e => e.Status).HasComment("订单状态");
entity.Property(e => e.TenantId).HasComment("租户");
entity.Property(e => e.TotalPrice)
.HasComment("价格")
.HasColumnType("money");
entity.Property(e => e.UpdatedAt)
.HasComment("修改时间")
.HasColumnType("datetime");
entity.Property(e => e.UserId).HasComment("用户Id");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_OrderItems>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_OrderI__3214EC077E53EC22");
entity.ToTable(tb => tb.HasComment("订单详情表"));
entity.Property(e => e.OrderId)
.HasMaxLength(64)
.HasComment("订单id");
entity.Property(e => e.PaymentInfo).HasComment("支付信息");
entity.Property(e => e.Product).HasComment("产品id、主键");
entity.Property(e => e.ProductId)
.HasMaxLength(100)
.HasComment("产品id");
entity.Property(e => e.RewardInfo).HasComment("发放奖励信息");
entity.Property(e => e.TenantId).HasComment("租户");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Products>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Products__3214EC07DC10A165");

View File

@ -0,0 +1,68 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 订单完成表
/// </summary>
public partial class T_Order: MultiTenantEntity
{
public virtual int Id { get; set; }
public override Guid TenantId { get; set; }
/// <summary>
/// 订单编号
/// </summary>
public virtual string OrderId { get; set; } = null!;
/// <summary>
/// 用户Id
/// </summary>
public virtual int UserId { get; set; }
/// <summary>
/// 订单创建时间
/// </summary>
public virtual DateTime OrderDate { get; set; }
/// <summary>
/// 订单支付时间
/// </summary>
public virtual DateTime PaymentDate { get; set; }
/// <summary>
/// 订单支付方式
/// </summary>
public virtual string PaymentMethod { get; set; } = null!;
/// <summary>
/// 购买的产品Id
/// </summary>
public virtual string ProductId { get; set; } = null!;
/// <summary>
/// 价格
/// </summary>
public virtual decimal TotalPrice { get; set; }
/// <summary>
/// 订单状态
/// </summary>
public virtual int Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public virtual DateTime CreatedAt { get; set; }
/// <summary>
/// 修改时间
/// </summary>
public virtual DateTime UpdatedAt { get; set; }
/// <summary>
/// 订单创建天
/// </summary>
public virtual DateOnly PaymentDay { get; set; }
}

View File

@ -0,0 +1,37 @@

namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 订单详情表
/// </summary>
public partial class T_OrderItems: MultiTenantEntity
{
public virtual int Id { get; set; }
public override Guid TenantId { get; set; }
/// <summary>
/// 产品id
/// </summary>
public virtual string ProductId { get; set; } = null!;
/// <summary>
/// 订单id
/// </summary>
public virtual string OrderId { get; set; } = null!;
/// <summary>
/// 发放奖励信息
/// </summary>
public virtual string? RewardInfo { get; set; }
/// <summary>
/// 产品id、主键
/// </summary>
public virtual int Product { get; set; }
/// <summary>
/// 支付信息
/// </summary>
public virtual string? PaymentInfo { get; set; }
}

View File

@ -1,11 +1,11 @@
using System;
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 用户货币表
/// </summary>
public partial class T_User_Currency: MultiTenantEntity
public partial class T_User_Currency : MultiTenantEntity
{
public virtual int Id { get; set; }
@ -40,4 +40,4 @@ public partial class T_User_Currency: MultiTenantEntity
public virtual int UserId { get; set; }
public override Guid TenantId { get; set; }
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Model.EnumModel
{
/// <summary>
/// 订单状态
/// </summary>
public enum OrderState
{
/// <summary>
/// 已下单
/// </summary>
= 0,
/// <summary>
/// 正在发货
/// </summary>
= 1,
/// <summary>
/// 已完成
/// </summary>
= 2,
/// <summary>
/// 发货失败
/// </summary>
= 3
}
}

View File

@ -1,40 +1,178 @@
using HuanMeng.DotNetCore.MultiTenant.Contract;
using HuanMeng.DotNetCore.Utility;
using HuanMeng.MiaoYu.Code.AppExtend;
using HuanMeng.MiaoYu.Code.Base;
using HuanMeng.MiaoYu.Code.DataAccess;
using HuanMeng.MiaoYu.Code.Payment;
using HuanMeng.MiaoYu.Code.Users;
using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
using HuanMeng.MiaoYu.Model.EnumModel;
using HuanMeng.MiaoYu.Model.EnumModel.User;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using System;
using System.Text;
namespace HuanMeng.MiaoYu.WebPayApi.Controllers
{
[Route("api/[controller]/")]
[ApiController]
public class PayController(ILogger<PayController> logger, IHttpContextAccessor httpContextAccessor) : ControllerBase
public class PayController(ILogger<PayController> logger, IHttpContextAccessor httpContextAccessor, IServiceProvider serviceProvider) : ControllerBase
{
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet("{tenant?}/{pay?}/{orderId?}")]
public async Task<string> Get(string? tenant, string? pay, string? orderId)
{
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;
}
return $"success";
}
///// <summary>
/////
///// </summary>
///// <returns></returns>
//[HttpGet("{tenant?}/{pay?}/{orderId?}")]
//public async Task<string> Get(string? tenant, string? pay, string? orderId)
//{
// 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;
// }
// return $"success";
//}
/// <summary>
/// ${tenant}/zfb/${orderId}
/// ${tenant}/zfb/${orderId} http://localhost:90/api/Pay/default/wx/WX0T1724769806U000002P001M001RLZ/c2e0468ed21e79ebb4f3164b2a3209ac
/// </summary>
/// <returns></returns>
[HttpPost("{tenant?}/{pay?}/{orderId?}/{sign?}")]
public async Task<string> Post(string? tenant, string? pay, string? orderId,string? sign)
public async Task<string> Post(string? tenant, string? pay, string? orderId, string? sign)
{
#region
var context = httpContextAccessor.HttpContext;
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 = RedisConnection.GetRedis(appConfig);
if (!redis.StringSetLock(baseKey, "", 3))
{
return "error;重复请求";
}
var temantInfo = serviceProvider.GetRequiredService<ITenantInfo>();
appConfig.ToITenantInfo(temantInfo);
DAO dao = new DAO(serviceProvider);
var intentOrder = await dao.daoDbMiaoYu.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 $"error;订单{((OrderState)intentOrder.Status).ToString()}";
}
intentOrder.Status = (int)OrderState.;
await dao.daoDbMiaoYu.context.SaveChangesAsync();
var product = await dao.daoDbMiaoYu.context.T_Products.Where(it => it.ProductId == intentOrder.ProductId).FirstOrDefaultAsync();
if (product == null)
{
intentOrder.Status = (int)OrderState.;
await dao.daoDbMiaoYu.context.SaveChangesAsync();
return $"error;订单不存在";
}
var user = await dao.daoDbMiaoYu.context.T_User.FirstOrDefaultAsync(it => it.Id == intentOrder.UserId);
if (user == null)
{
intentOrder.Status = (int)OrderState.;
await dao.daoDbMiaoYu.context.SaveChangesAsync();
return $"error;用户不存在";
}
var chargeMoneyCount = dao.daoDbMiaoYu.context.T_Order.Count(it => it.UserId == intentOrder.UserId && it.ProductId == it.ProductId);
var productReward = await dao.daoDbMiaoYu.context.T_Products_Reward.Where(it => it.ProductId == intentOrder.ProductId).ToListAsync();
if (productReward != null && productReward.Count > 0)
{
using (IDbContextTransaction transaction = dao.daoDbMiaoYu.context.Database.BeginTransaction())
{
try
{
//List<T_User_Currency> user_Currencies = new List<T_User_Currency>();
foreach (var reward in productReward)
{
var money = reward.Money;
if (product.IsFirstCharge && chargeMoneyCount == 0)
{
money = reward.FirstChargeMoney ?? reward.Money;
}
var currency = (UserCurrencyType)reward.CurrencyType;
var userCurrency = new T_User_Currency();
user.ConsumeMoneyNoWork(currency, money, dao, userCurrency, orderId);
}
T_Order order = new T_Order()
{
OrderId = orderId,
CreatedAt = DateTime.Now,
OrderDate = intentOrder.IntentDate,
PaymentDate = DateTime.Now,
PaymentDay = DateOnly.FromDateTime(DateTime.Now),
PaymentMethod = pay,
ProductId = intentOrder.ProductId,
Status = (int)OrderState.,
TenantId = intentOrder.TenantId,
TotalPrice = intentOrder.Price,
UpdatedAt = DateTime.Now,
UserId = intentOrder.UserId,
};
T_OrderItems t_OrderItems = new T_OrderItems()
{
OrderId = orderId,
PaymentInfo = "",
Product = product.Id,
ProductId = intentOrder.ProductId,
RewardInfo = JsonConvert.SerializeObject(productReward),
TenantId = intentOrder.TenantId,
};
dao.daoDbMiaoYu.context.T_OrderItems.Add(t_OrderItems);
dao.daoDbMiaoYu.context.T_Order.Add(order);
intentOrder.Status = (int)OrderState.;
await dao.daoDbMiaoYu.context.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception ex)
{
await transaction.RollbackAsync();
intentOrder.Status = (int)OrderState.;
await dao.daoDbMiaoYu.context.SaveChangesAsync();
throw;
}
}
}
//redis.ListRightPush("myQueue", "value3");
//await redis.PublishAsync("order_rewards_queue", orderData);
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))
{
@ -42,6 +180,7 @@ namespace HuanMeng.MiaoYu.WebPayApi.Controllers
logger.LogInformation($"请求支付回调接口,请求路径: {context.Request.Path}, 请求Body: {bodyContent}");
context.Request.Body.Position = 0;
}
redis.KeyDelete(baseKey);
return $"success";
}
}