122 lines
6.7 KiB
C#
122 lines
6.7 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using MAX.Framework.Commons;
|
|
using MAX.Framework.Validation;
|
|
using Store.Shops.Dtos;
|
|
using Store.Shops.Entities;
|
|
using Store.Shops.Mappers;
|
|
using YourNamespace;
|
|
|
|
namespace Store.Shops.Services;
|
|
|
|
public sealed partial class ShopService
|
|
{
|
|
/// <summary>选品列表跨月时重置300条额度,并同步店铺表;同店多条登录记录只处理一次。</summary>
|
|
private async Task RefreshQuotas(List<ShopDetailsInfo> shops, CancellationToken ct)
|
|
{
|
|
using var work = db.CreateUnitOfWork();
|
|
work.IsolationLevel = System.Data.IsolationLevel.Serializable;
|
|
work.GetOrBeginTransaction();
|
|
var orm = work.Orm;
|
|
// shortcut: 旧表仅保存月份;需要区分跨年同月额度时升级为年月字段。
|
|
var month = DateTime.Now.Month;
|
|
foreach (var group in shops.Where(s => !string.IsNullOrEmpty(s.ShopId)).GroupBy(s => s.ShopId).OrderBy(g => g.Key, StringComparer.Ordinal))
|
|
{
|
|
var quota = await orm.Select<ShopQuotaEntity>().Where(q => q.ShopId == group.Key).ForUpdate().FirstAsync(ct);
|
|
if (quota == null)
|
|
{
|
|
quota = new() { ShopId = group.Key, ShopAccount = group.First().ShopAccount, AddProductMonth = month, AddProductRemaining = 300 };
|
|
await orm.Insert(quota).ExecuteAffrowsAsync(ct);
|
|
}
|
|
else if (quota.AddProductMonth != month)
|
|
{
|
|
quota.AddProductMonth = month;
|
|
quota.AddProductRemaining = 300;
|
|
await orm.Update<ShopQuotaEntity>().Where(q => q.ShopId == group.Key)
|
|
.Set(q => q.AddProductMonth, month).Set(q => q.AddProductRemaining, 300).ExecuteAffrowsAsync(ct);
|
|
}
|
|
await orm.Update<ShopEntity>().Where(s => s.ShopId == group.Key)
|
|
.Set(s => s.AddProductMonth, (byte)quota.AddProductMonth)
|
|
.Set(s => s.AddProductRemaining, quota.AddProductRemaining).ExecuteAffrowsAsync(ct);
|
|
foreach (var item in group)
|
|
{
|
|
item.AddProductMonth = (byte)quota.AddProductMonth;
|
|
item.AddProductRemaining = quota.AddProductRemaining;
|
|
}
|
|
}
|
|
ct.ThrowIfCancellationRequested();
|
|
work.Commit();
|
|
}
|
|
|
|
/// <summary>管理员设置明确指定店铺的共享额度,同步列表读取的店铺字段。</summary>
|
|
public async Task UpdateQuota(QuotaRequest request, CancellationToken ct)
|
|
{
|
|
RequestValidator.Validate(request);
|
|
Ids(request.ShopIds);
|
|
if (request.RemainCount < 0) throw new ValidationException("剩余额度不能小于0");
|
|
RequireAdmin(await Actor());
|
|
using var work = db.CreateUnitOfWork();
|
|
work.IsolationLevel = System.Data.IsolationLevel.Serializable;
|
|
work.GetOrBeginTransaction();
|
|
var orm = work.Orm;
|
|
var existing = await orm.Select<ShopQuotaEntity>().Where(q => request.ShopIds.Contains(q.ShopId)).ForUpdate().ToListAsync(ct);
|
|
if (request.ShopIds.Except(existing.Select(q => q.ShopId)).Any()) throw new AppException("部分店铺尚未建立额度记录");
|
|
await orm.Update<ShopQuotaEntity>().Where(q => request.ShopIds.Contains(q.ShopId))
|
|
.Set(q => q.AddProductRemaining, request.RemainCount).ExecuteAffrowsAsync(ct);
|
|
await orm.Update<ShopEntity>().Where(s => request.ShopIds.Contains(s.ShopId))
|
|
.Set(s => s.AddProductRemaining, request.RemainCount).ExecuteAffrowsAsync(ct);
|
|
ct.ThrowIfCancellationRequested();
|
|
work.Commit();
|
|
}
|
|
|
|
/// <summary>管理员按记录ID或登录名分配选品操作员,空账号表示解除分配。</summary>
|
|
public async Task Assign(AssignRequest request, CancellationToken ct)
|
|
{
|
|
RequestValidator.Validate(request);
|
|
if (request.DbIds is not { Length: > 0 } && request.ShopLoginNames is not { Length: > 0 })
|
|
throw new ValidationException("请选择店铺记录或登录名");
|
|
if (request.DbIds?.Any(id => id <= 0) == true) throw new ValidationException("记录ID必须大于0");
|
|
if (request.ShopLoginNames != null) Ids(request.ShopLoginNames);
|
|
RequireAdmin(await Actor());
|
|
if (request.OperateSubSaName != "") await users.GetUser(request.OperateSubSaName);
|
|
var update = db.Update<ShopEntity>();
|
|
if (request.DbIds is { Length: > 0 }) update.Where(s => request.DbIds.Contains(s.Id));
|
|
else update.Where(s => request.ShopLoginNames!.Contains(s.LoginName));
|
|
if (await update.Set(s => s.OperateSubSaName, request.OperateSubSaName)
|
|
.Set(s => s.AddSubSaTime, DateTime.Now).ExecuteAffrowsAsync(ct) == 0)
|
|
throw new AppException("未找到指定店铺");
|
|
}
|
|
|
|
/// <summary>查询授权店铺对应的ERP商户余额,不能仅凭外部商户ID读取他人余额。</summary>
|
|
public async Task<ShopPage<ErpAccountInfo>> ErpMerchants(ErpRequest request, CancellationToken ct)
|
|
{
|
|
RequestValidator.Validate(request);
|
|
Page(request.Page, request.PageSize);
|
|
if (request.CorporateAccountUserId == null && request.ManageUserId == null)
|
|
throw new ValidationException("必须指定公司账号或管理账号");
|
|
if (request.CorporateAccountUserId <= 0 || request.ManageUserId <= 0)
|
|
throw new ValidationException("ERP账号ID必须大于0");
|
|
var actor = await Actor();
|
|
var ids = await VisibleIds(actor, ct);
|
|
var linked = await db.Select<ErpShopEntity>().Where(s => ids.Contains(s.AppKey))
|
|
.WhereIf(!string.IsNullOrEmpty(request.ShopId), s => s.AppKey == request.ShopId).ToListAsync(ct);
|
|
var managers = new List<long>();
|
|
if (request.ManageUserId.HasValue)
|
|
{
|
|
if (!linked.Any(s => s.ManageUserId == request.ManageUserId)) throw new AppException("无权查询该ERP管理账号");
|
|
managers.Add(request.ManageUserId.Value);
|
|
}
|
|
if (request.CorporateAccountUserId.HasValue)
|
|
{
|
|
if (!linked.Any(s => s.CorporateAccountUserId == request.CorporateAccountUserId))
|
|
throw new AppException("无权查询该ERP公司账号");
|
|
managers.AddRange(await db.Select<ErpGroupEntity>()
|
|
.Where(g => g.CorporateAccountUserId == request.CorporateAccountUserId)
|
|
.ToListAsync(g => g.ManageUserId, ct));
|
|
}
|
|
var query = db.Select<ErpAccountEntity>().Where(a => managers.Contains(a.UserId));
|
|
var count = request.NotCount ? -1 : await query.CountAsync(ct);
|
|
var rows = await query.OrderByDescending(a => a.Balance).OrderBy(a => a.Id).Page(request.Page, request.PageSize).ToListAsync(ct);
|
|
return new(rows.Select(new ShopDetailsMapper().Map).ToList(), count);
|
|
}
|
|
}
|