Files
KJD_WebService/KJD_WebService/Services/Users/UserService.cs
T
2026-09-27 22:24:27 +08:00

473 lines
14 KiB
C#
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using FreeSql;
using KJD_Web.Dtos.Users;
using KJD_Web.Model;
using KJD_Web.Model.ShopModel;
using KJD_Web.Requests.Users;
using KJD_Web.Utils;
using MAX.Core.DependencyInjection;
using MAX.Core.Logger;
using NaiBa.Util.Extension;
using Store.Contracts.Order.Entitys;
using Store.Contracts.User.Entitys;
using Store.Contracts.User.Enums;
using Store.Contracts.User.Interfaces;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using Ubiety.Dns.Core;
using YourNamespace;
namespace KJD_Web.Services.Users
{
public partial class UserService : IUserService, ITransientDependency
{
/// <summary>
/// 商铺续费每月30
/// </summary>
private const int MinShopPointsPerMonth = 30;
private const int UserNameMaxLength = 20;
private const int ShopIdMaxLength = 50;
private const int RemarkMaxLength = 255;
private const int MaxRenewDuration = 120;
private readonly IFreeSql _freeSql;
private readonly ILoggerFacade _logger;
public UserService(IFreeSql freeSql, ILoggerFacade logger)
{
_freeSql = freeSql ?? throw new ArgumentNullException(nameof(freeSql));
_logger = logger;
}
public bool IsOem(string userName)
{
return GetOEMByUserName(userName) != null;
}
public UserEntity GetUserByUserName(string userName)
{
if (string.IsNullOrEmpty(userName)) return null;
var user = _freeSql.Select<UserEntity>().Where(a => a.UserName == userName).First();
if (user != null)
{
if (user.IsMainUser == false)
{
var mainUser = _freeSql.Select<UserEntity>()
.Where(a => a.UserName == user.ParentUserName)
.First();
if (mainUser != null)
{
user.OemId = mainUser.OemId;
user.PostagePerOrder = mainUser.PostagePerOrder;
user.RefundPostagePerOrder = mainUser.RefundPostagePerOrder;
user.GiftOemAmountPerOrder = mainUser.GiftOemAmountPerOrder;
user.SyncLogisticsPerOrder = mainUser.SyncLogisticsPerOrder;
}
}
}
return user;
}
/// <summary>
/// 获取用户包含子账户
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public List<UserEntity> GetUserAndSubUser(string userName)
{
if (string.IsNullOrEmpty(userName)) return null;
var mainUser = _freeSql.Select<UserEntity>().Where(a => a.UserName == userName).First();
if (mainUser == null) return null;
List<UserEntity> allUsers = [mainUser];
// 3. 这些主账号对应的子账号
var subUsers = _freeSql.Select<UserEntity>()
.Where(u => u.ParentUserName == mainUser.UserName)
.ToList();
// 4. 合并,去重
allUsers = allUsers
.Concat(subUsers)
.Distinct()
.ToList();
return allUsers;
}
/// <summary>
/// 商铺续费
/// </summary>
/// <param name="request">续费请求</param>
public ShopRenewResponse ShopRenew(ShopRenewRequest request)
{
ShopRenewResponse response = new ShopRenewResponse();
ValidateRequest(request);
string userName = request.UserName.Trim();
string shopId = request.ShopId.Trim();
string remark = string.IsNullOrWhiteSpace(request.Remark) ? null : request.Remark.Trim();
_freeSql.Transaction(() =>
{
UserEntity user = _freeSql.Select<UserEntity>()
.Where(a => a.UserName == userName)
.ForUpdate()
.First();
if (user == null)
{
throw new InvalidOperationException("不存在的用户");
}
ShopEntity shop = _freeSql.Select<ShopEntity>()
.Where(a => a.ShopId == shopId && a.UserName == user.UserName)
.ForUpdate()
.First();
if (shop == null)
{
throw new InvalidOperationException("不存在的商铺");
}
if (!string.Equals(shop.UserName, userName, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("该商铺不属于当前用户");
}
int shopPointsPerMonth = Math.Max(MinShopPointsPerMonth, user.ShopPointsPerMonth);
int deltaPoints = shopPointsPerMonth * request.RenewDuration;
if (user.Points < deltaPoints)
{
throw new InvalidOperationException("余额不足");
}
int newPoints = (int)user.Points - deltaPoints;
DateTime now = DateTime.Now;
UserPointsShopExpireEntity currentExpire = _freeSql.Select<UserPointsShopExpireEntity>()
.Where(a => a.ShopId == shopId)
.ForUpdate()
.First();
DateTime expireBaseTime = now;
if (currentExpire != null && currentExpire.ExpireTime > 0)
{
DateTime currentExpireTime = TimeUtils.StampToDateTime(currentExpire.ExpireTime);
if (currentExpireTime > expireBaseTime)
{
expireBaseTime = currentExpireTime;
}
}
int newExpireTime = CalculateNewExpireTime(expireBaseTime, request.RenewDuration);
int affectedUser = _freeSql.Update<UserEntity>()
.Set(a => a.Points, newPoints)
.Where(a => a.UserName == userName && a.Points == user.Points)
.ExecuteAffrows();
if (affectedUser != 1)
{
throw new InvalidOperationException("账户已发生改变,请刷新账户后重新操作");
}
for (int i = 0; i < request.RenewDuration; i++)
{
now = now.AddSeconds(i);
decimal recordNewPoints = user.Points - (decimal)shopPointsPerMonth * (i + 1);
UserPointsRecordEntity item = new UserPointsRecordEntity
{
OptionType = "续费",
OperatorType = "用户",
OperatorName = userName,
UserName = userName,
UserNick = user.NickName,
DeltaPoints = shopPointsPerMonth,
NewPoints = recordNewPoints,
ShopId = shop.ShopId,
ShopAccount = shop.ShopAccount,
Remark = remark,
AddTime = now
};
int affectedRecord = _freeSql.Insert(item).ExecuteAffrows();
if (affectedRecord != 1)
{
throw new InvalidOperationException("新增操作记录失败,请稍候重试");
}
}
if (currentExpire == null)
{
UserPointsShopExpireEntity expire = new UserPointsShopExpireEntity
{
ShopId = shopId,
ExpireTime = newExpireTime,
AddTime = now,
MdyTime = now
};
int affectedExpire = _freeSql.Insert(expire).ExecuteAffrows();
if (affectedExpire != 1)
{
throw new InvalidOperationException("新增商铺过期时间失败,请稍候重试");
}
}
else
{
int affectedExpire = _freeSql.Update<UserPointsShopExpireEntity>()
.Set(a => a.ExpireTime, newExpireTime)
.Set(a => a.MdyTime, now)
.Where(a => a.Id == currentExpire.Id && a.ExpireTime == currentExpire.ExpireTime)
.ExecuteAffrows();
if (affectedExpire != 1)
{
throw new InvalidOperationException("店铺已发生改变,请刷新店铺后重新操作");
}
}
response.ShopId = request.ShopId;
response.UserPoints = newPoints;
response.ExpireTime‌ = newExpireTime;
});
return response;
}
private static void ValidateRequest(ShopRenewRequest request)
{
if (request == null)
{
throw new ArgumentException("请求参数不能为空", nameof(request));
}
if (string.IsNullOrWhiteSpace(request.UserName))
{
throw new ArgumentException("用户名不能为空", nameof(request.UserName));
}
if (request.UserName.Trim().Length > UserNameMaxLength)
{
throw new ArgumentException("用户名长度不能超过20个字符", nameof(request.UserName));
}
if (string.IsNullOrWhiteSpace(request.ShopId))
{
throw new ArgumentException("店铺ID不能为空", nameof(request.ShopId));
}
if (request.ShopId.Trim().Length > ShopIdMaxLength)
{
throw new ArgumentException("店铺ID长度不能超过50个字符", nameof(request.ShopId));
}
if (request.RenewDuration <= 0)
{
throw new ArgumentException("续费时长必须大于0", nameof(request.RenewDuration));
}
if (request.RenewDuration > MaxRenewDuration)
{
throw new ArgumentException("续费时长不能超过120个月", nameof(request.RenewDuration));
}
if (!string.IsNullOrEmpty(request.Remark) && request.Remark.Trim().Length > RemarkMaxLength)
{
throw new ArgumentException("备注长度不能超过255个字符", nameof(request.Remark));
}
}
private static int CalculateNewExpireTime(DateTime expireBaseTime, int renewDuration)
{
DateTime newExpireDateTime;
try
{
newExpireDateTime = expireBaseTime.AddMonths(renewDuration);
}
catch (ArgumentOutOfRangeException)
{
throw new InvalidOperationException("续费时长超出允许范围");
}
if (newExpireDateTime > TimeUtils.StampToDateTime(int.MaxValue))
{
throw new InvalidOperationException("续费时间超出系统支持范围");
}
return TimeUtils.DateTimeToTimestampSeconds(newExpireDateTime);
}
/// <summary>
/// 更新用户
/// </summary>
/// <param name="userinfo"></param>
/// <exception cref="Exception"></exception>
public void UpdateUser(CUUserInfoRequest userinfo)
{
using var work = _freeSql.CreateUnitOfWork();
var trFreeSql = work.Orm;
var oldUser = trFreeSql.Select<UserEntity>()
.Where(a => a.Id == userinfo.Id)
.First();
if (oldUser == null) throw new Exception("错误的用户");
if (string.IsNullOrEmpty(userinfo.NickName) || string.IsNullOrEmpty(userinfo.Mobile)) throw new Exception("信息不正确");
if (userinfo.Mobile.Length != 11) throw new Exception("信息不正确");
var update = trFreeSql.Update<UserEntity>();
if (!string.IsNullOrEmpty(userinfo.NickName))
update = update.Set(a => a.NickName, userinfo.NickName);
if (!string.IsNullOrEmpty(userinfo.UserName))
update = update.Set(a => a.UserName, userinfo.UserName);
if (!string.IsNullOrEmpty(userinfo.Mobile))
update = update.Set(a => a.Mobile, userinfo.Mobile);
if (!string.IsNullOrEmpty(userinfo.CompanyName))
update = update.Set(a => a.CompanyName, userinfo.CompanyName);
if (!string.IsNullOrEmpty(userinfo.Password))
update = update.Set(a => a.Password, userinfo.Password);
if (userinfo.GroupId.HasValue)
update = update.Set(a => a.GroupId, userinfo.GroupId.Value);
if (string.IsNullOrEmpty(userinfo.CardId))
update = update.Set(a => a.CardId, userinfo.CardId);
if (!string.IsNullOrEmpty(userinfo.Notes))
update = update.Set(a => a.Notes, userinfo.Notes);
if (userinfo.SaLevel.HasValue)
update = update.Set(a => a.SaLevel, (short)userinfo.SaLevel.Value);
if (userinfo.Authority != null)
update = update.Set(a => a.Authority, userinfo.Authority);
if (userinfo.ForbiddenPage != null)
update = update.Set(a => a.ForbiddenPage, userinfo.ForbiddenPage);
if (userinfo.ShopPointsPerMonth.HasValue)
update = update.Set(a => a.ShopPointsPerMonth, userinfo.ShopPointsPerMonth.Value);
if (userinfo.PostagePerOrder.HasValue)
update = update.Set(a => a.PostagePerOrder, userinfo.PostagePerOrder.Value);
if (userinfo.RefundPostagePerOrder.HasValue)
update = update.Set(a => a.RefundPostagePerOrder, userinfo.RefundPostagePerOrder.Value);
if (userinfo.GiftOemAmountPerOrder.HasValue)
update = update.Set(a => a.GiftOemAmountPerOrder, userinfo.GiftOemAmountPerOrder.Value);
if (userinfo.SyncLogisticsPerOrder.HasValue)
update = update.Set(a => a.SyncLogisticsPerOrder, userinfo.SyncLogisticsPerOrder.Value);
//主账户允许修改OEM
if (oldUser.IsMainUser)
{
update = update.Set(a => a.OemId, userinfo.OemId);
}
string sql = update.Where(a => a.Id == userinfo.Id).ToSql();
var updateCount = update
.Where(a => a.Id == userinfo.Id)
.ExecuteAffrows();
if (updateCount != 1)
{
throw new Exception("修改失败");
}
if (oldUser.IsMainUser)//主账号允许结算
{
if (oldUser.OemId != userinfo.OemId)
{
//更换oem 需要结算
if (string.IsNullOrEmpty(oldUser.OemId) == false)
{
//移除旧Oem
var oem = GetOEMByOemId(oldUser.OemId);
if (oem != null)
{
SettleOemFlows(oem.OemOwner, work.GetOrBeginTransaction());
}
}
else
{
//空OEM 转非空
SettleUserFlows(userinfo.UserName, work.GetOrBeginTransaction());
}
}
}
work.Commit();
}
/// <summary>
/// 是否可以消费
/// </summary>
/// <param name="userName"></param>
/// <param name="type"></param>
/// <param name="consumeAmount"></param>
/// <returns></returns>
public bool CanAfford(string userName, UserPaymentTypes type, decimal consumeAmount)
{
var user = GetUserByUserName(userName);
if (user == null) return false;
// 消费金额必须大于 0
if (user.Balance <= 0) return false;
if (type != UserPaymentTypes.同步单号) return false;
consumeAmount = (user.SyncLogisticsPerOrder ?? 0m) + consumeAmount;
return user.Balance >= consumeAmount;
}
/// <summary>
/// 用户消费付款记录
/// </summary>
/// <param name="userName"></param>
/// <param name="orderId"></param>
/// <param name="type"></param>
/// <param name="tarn"></param>
/// <exception cref="Exception"></exception>
public void UserPayment(string userName, string orderId, UserPaymentTypes type, DbTransaction tarn = null)
{
using var work = tarn != null ? _freeSql.CreateUnitOfWork(tarn) : _freeSql.CreateUnitOfWork();
var trFreeSql = work.Orm;
var user = trFreeSql.Select<UserEntity>()
.Where(a => a.UserName == userName)
.First();
if (user == null)
{
throw new Exception("用户不存在");
}
if (type != UserPaymentTypes.同步单号) throw new Exception("不支持的类型");
var payItem = new UserPaymentRecordEntity
{
Type = (int)type,
Amount = (user.SyncLogisticsPerOrder ?? 0.0m) + 1.9m,
UserName = user.UserName,
PlatformCode = "WEISHOP",
OrderId = orderId,
CreateBy = user.UserName,
CreateTime = DateTime.Now,
Remark = "同步物流:",
CounterpartyAccountName = user.UserName,
};
if (user.IsOEMTenant)
{
payItem.OemAmount = user.SyncLogisticsPerOrder;
}
payItem.Balance = user.Balance - payItem.Amount;
var affrows = trFreeSql.Insert<UserPaymentRecordEntity>(payItem).ExecuteAffrows();
if (affrows != 1)
{
_logger.Error($"付款失败:{userName},{orderId},{type}");
throw new Exception("付款失败");
}
affrows = trFreeSql.Update<UserEntity>()
.Set(a => a.Balance - payItem.Amount)
.Where(a => a.UserName == user.UserName)
.Where(a => a.Balance >= payItem.Amount)
.ExecuteAffrows();
if (affrows != 1)
{
_logger.Error($"付款失败,余额不足:{userName},{orderId},{type}");
throw new Exception("余额不足");
}
work.Commit();
}
}
}