HuanMengProject/src/0-core/HuanMeng.MiaoYu.Code/Order/OrderBLL.cs
2024-09-27 20:43:40 +08:00

301 lines
12 KiB
C#

using HuanMeng.MiaoYu.Code.AppExtend;
using HuanMeng.MiaoYu.Code.Cache.Special;
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.Dto.Order;
using HuanMeng.MiaoYu.Model.EnumModel.User;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Order
{
/// <summary>
/// 订单数据
/// </summary>
public class OrderBLL : MiaoYuBase
{
public OrderBLL(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
/// <summary>
/// 创建订单
/// </summary>
/// <param name="paymentMethod"></param>
/// <param name="productId"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="NullReferenceException"></exception>
/// <exception cref="Exception"></exception>
public async Task<BaseResponse<IntentOrderDto>> CreateOrder(string paymentMethod, string productId)
{
if (_UserId == 0)
{
throw new ArgumentNullException("未登录");
}
if (string.IsNullOrEmpty(productId))
{
throw new ArgumentNullException("产品不能为空");
}
ProductEntityCache productEntityCache = new ProductEntityCache(this);
var products = productEntityCache.GetDataList();
var product = products.FirstOrDefault(it => it.ProductId == productId);
if (product == null)
{
throw new NullReferenceException("未找到所属产品");
}
var redisLock = $"lock:payment:{_UserId}:{productId}";
if (!RedisCache.StringSetLock(redisLock, "", 5))
{
throw new ArgumentNullException("重复创建订单");
}
//productEntityCache.get
IntentOrderDto intentOrderDto = null;
//创建订单
try
{
var ip = HttpContextAccessor.HttpContext.GetClientIpAddress();
var price = product.Price;
var payment = PaymentExtend.GetPayment(paymentMethod, this);
UserInfoBLL userInfo = new UserInfoBLL(Dao, _UserId);
if (userInfo.User.IsTest ?? false)
{
price = (decimal)0.01;
}
(var orderId, var order) = await payment.CreateOrder(product.Id, product.ProductName, price, product, ip);
var t = product.ToIntentOrder(paymentMethod, orderId);
t.UserId = _UserId;
Dao.daoDbMiaoYu.context.Add(t);
await Dao.daoDbMiaoYu.context.SaveChangesAsync();
intentOrderDto = new IntentOrderDto()
{
OrderId = orderId,
Payment = order
};
RedisCache.KeyDelete(redisLock);
}
catch (Exception ex)
{
RedisCache.KeyDelete(redisLock);
throw new Exception("创建订单失败");
}
return new BaseResponse<IntentOrderDto>(ResonseCode.Success, "", intentOrderDto);
}
/// <summary>
/// 获取订单状态
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
public async Task<BaseResponse<bool>> GetOrderRewardsInfo(string orderId)
{
var tips = await Dao.daoDbMiaoYu.context.T_OrderItems.Where(it => it.OrderId == orderId).Select(it => it.RewardTips).FirstOrDefaultAsync();
if (string.IsNullOrEmpty(tips))
{
return new BaseResponse<bool>(ResonseCode.Success, "", false);
}
return new BaseResponse<bool>(ResonseCode.Success, tips, true);
}
/// <summary>
/// 购买产品
/// </summary>
/// <param name="productId"></param>
/// <param name="buyCount"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<BaseResponse<bool>> BuyProduct(string productId, int buyCount = 1)
{
if (buyCount < 1)
{
buyCount = 1;
}
var product = await Dao.daoDbMiaoYu.context.T_Products.Where(it => it.ProductId == productId && it.ProductType == 1).FirstOrDefaultAsync();
if (product == null)
{
throw new Exception("未找到产品");
}
var image = product.ProductImgId.GetImageUrl(this);
var user = await Dao.daoDbMiaoYu.context.T_User.FirstOrDefaultAsync(it => it.Id == _UserId);
if (user == null)
{
throw new Exception("用户不存在");
}
var baseKey = $"pay:lock:{_UserId}:{productId}";
if (!RedisCache.StringSetLock(baseKey, "", 10))
{
throw new Exception("正在购买中");
}
using (IDbContextTransaction transaction = Dao.daoDbMiaoYu.context.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
try
{
var price = (((int)product.Price) * buyCount);
user.ConsumeMoneyNoWork(UserCurrencyType., -price, Dao, title: $"购买{product.ProductName}*{buyCount}");
for (int i = 0; i < buyCount; i++)
{
var productReward = await Dao.daoDbMiaoYu.context.T_Products_Reward.Where(it => it.ProductId == product.ProductId).ToListAsync();
if (productReward != null && productReward.Count > 0)
{
List<string> tips = new List<string>();
foreach (var reward in productReward)
{
var money = reward.Money;
var currency = (UserCurrencyType)reward.CurrencyType;
var userCurrency = new T_User_Currency();
CurrencyTransactionParams currencyTransactionParams = new CurrencyTransactionParams()
{
UserCurrencyType = currency,
Money = money,
ImageUrl = image,
Currency = userCurrency,
Products = product
};
user.ConsumeMoneyNoWork(currencyTransactionParams, Dao);
if (currencyTransactionParams.Log != null)
{
currencyTransactionParams.Log.IsHide = true;
}
}
Dao.daoDbMiaoYu.context.SaveChanges();
}
}
await transaction.CommitAsync();
}
catch (Exception ex)
{
await transaction.RollbackAsync();
RedisCache.KeyDelete(baseKey);
throw ex;
}
}
RedisCache.KeyDelete(baseKey);
return new BaseResponse<bool>(ResonseCode.Success, $"购买成功,获得{product.ProductName}*{buyCount}", true) { };
}
}
/// <summary>
/// 订单扩展类
/// </summary>
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<bool> OrderRewardsAsync(this T_Products product, T_User user, string pay, string orderId, decimal price, DateTime intentDate, DAO dao)
{
using (IDbContextTransaction transaction = dao.daoDbMiaoYu.context.Database.BeginTransaction())
{
try
{
await OrderRewardsNoWorkAsync(product, user, pay, orderId, price, intentDate, dao);
await transaction.CommitAsync();
}
catch (Exception ex)
{
await transaction.RollbackAsync();
return false;
}
}
return true;
}
/// <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_OrderItems orderItems = null)
{
var userId = user.Id;
var chargeMoneyCount = dao.daoDbMiaoYu.context.T_Order.Count(it => it.UserId == userId && it.ProductId == product.ProductId);
var productReward = await dao.daoDbMiaoYu.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();
user.ConsumeMoneyNoWork(currency, money, dao, userCurrency, orderId);
tips.Add($"获得{currency}*{money}");
if (product.IsFirstCharge && chargeMoneyCount == 0 && reward.FirstChargeMoney > 0)
{
user.ConsumeMoneyNoWork(currency, reward.FirstChargeMoney ?? 0, dao, userCurrency, orderId, $"首充赠送{currency}{reward.FirstChargeMoney}");
tips.Add($"首充赠送{currency}*{money}");
}
}
var rewardTips = string.Join(',', tips.ToArray());
T_Order order = new T_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_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.daoDbMiaoYu.context.T_OrderItems.Add(orderItems);
dao.daoDbMiaoYu.context.T_Order.Add(order);
await dao.daoDbMiaoYu.context.SaveChangesAsync();
}
}
}
}