473 lines
14 KiB
C#
473 lines
14 KiB
C#
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();
|
||
}
|
||
|
||
|
||
|
||
}
|
||
}
|