using FoodLabeling.Application.Services.DbModels; using FoodLabeling.Domain.Entities; using SqlSugar; using Volo.Abp; using Yi.Framework.SqlSugarCore.Abstractions; namespace FoodLabeling.Application.Helpers; /// /// Region(fl_group.Id)与 Location(location.Id)范围解析:Region 落库对应 location.GroupName。 /// public static class LocationScopeBindingHelper { /// /// 列表筛选:门店 Id 优先,否则 Region(groupId),否则 Company(partnerId);均未传返回 null。 /// public static async Task?> ResolveFilteredLocationIdsForListAsync( ISqlSugarClient db, string? partnerId, string? groupId, string? locationId) { var locId = locationId?.Trim(); if (!string.IsNullOrWhiteSpace(locId)) { if (!Guid.TryParse(locId, out var locationGuid)) { return new List(); } var exists = await db.Queryable() .AnyAsync(x => !x.IsDeleted && x.Id == locationGuid); return exists ? new List { locId } : new List(); } var gid = groupId?.Trim(); var pid = partnerId?.Trim(); if (string.IsNullOrWhiteSpace(pid) && string.IsNullOrWhiteSpace(gid)) { return null; } var q = db.Queryable().Where(x => !x.IsDeleted); if (!string.IsNullOrWhiteSpace(gid)) { var g = await db.Queryable() .FirstAsync(x => !x.IsDeleted && x.Id == gid); if (g is null) { return new List(); } var gName = g.GroupName?.Trim() ?? string.Empty; var partner = await db.Queryable() .FirstAsync(x => !x.IsDeleted && x.Id == g.PartnerId); var pName = partner?.PartnerName?.Trim() ?? string.Empty; q = q.Where(x => x.GroupName == gName && x.Partner == pName); } else if (!string.IsNullOrWhiteSpace(pid)) { var partner = await db.Queryable() .FirstAsync(x => !x.IsDeleted && x.Id == pid); if (partner is null) { return new List(); } var pName = partner.PartnerName?.Trim() ?? string.Empty; q = q.Where(x => x.Partner == pName); } return await q.Select(x => SqlFunc.ToString(x.Id)).ToListAsync(); } /// /// 列表筛选:按门店 Id 优先,否则按 Region(groupId)解析门店主键;均未传返回 null。 /// public static async Task?> ResolveScopedLocationIdsAsync( ISqlSugarClient db, string? groupId, string? locationId) { var locId = locationId?.Trim(); if (!string.IsNullOrWhiteSpace(locId)) { if (!Guid.TryParse(locId, out var locationGuid)) { return new List(); } var exists = await db.Queryable() .AnyAsync(x => !x.IsDeleted && x.Id == locationGuid); return exists ? new List { locId } : new List(); } var gid = groupId?.Trim(); if (string.IsNullOrWhiteSpace(gid)) { return null; } return await ResolveLocationIdsFromGroupIdsAsync(db, new List { gid }); } /// /// 将 Company(partnerId)、Region(groupIds)与显式 locationIds 合并为去重后的门店 Id 列表。 /// public static Task> MergeToLocationIdsAsync( ISqlSugarClient db, string? partnerId, IReadOnlyList? groupIds, IReadOnlyList? locationIds) => MergeToLocationIdsAsync(db, string.IsNullOrWhiteSpace(partnerId) ? null : new[] { partnerId.Trim() }, groupIds, locationIds); /// /// 将 Company(partnerIds)、Region(groupIds)与显式 locationIds 合并为去重后的门店 Id 列表。 /// public static async Task> MergeToLocationIdsAsync( ISqlSugarClient db, IReadOnlyList? partnerIds, IReadOnlyList? groupIds, IReadOnlyList? locationIds) { var merged = new HashSet(StringComparer.Ordinal); var fromPartner = await ResolveLocationIdsFromPartnerIdsAsync(db, partnerIds); foreach (var id in fromPartner) { merged.Add(id); } var fromGroups = await ResolveLocationIdsFromGroupIdsAsync(db, groupIds); foreach (var id in fromGroups) { merged.Add(id); } foreach (var id in NormalizeIds(locationIds)) { merged.Add(id); } return merged.ToList(); } /// /// 根据已绑定门店反推适用的 Company Id(fl_partner.Id)。 /// public static async Task> ResolvePartnerIdsFromLocationIdsAsync( ISqlSugarClient db, IReadOnlyList locationIds) { var ids = NormalizeIds(locationIds); if (ids.Count == 0) { return new List(); } var guidList = ids.Where(x => Guid.TryParse(x, out _)).Select(Guid.Parse).ToList(); if (guidList.Count == 0) { return new List(); } var locs = await db.Queryable() .Where(x => !x.IsDeleted && guidList.Contains(x.Id)) .ToListAsync(); if (locs.Count == 0) { return new List(); } var partnerNames = locs .Select(x => x.Partner?.Trim()) .Where(x => !string.IsNullOrEmpty(x)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); if (partnerNames.Count == 0) { return new List(); } var partners = await db.Queryable() .Where(x => !x.IsDeleted) .ToListAsync(); var partnerIdSet = new HashSet(StringComparer.Ordinal); foreach (var name in partnerNames) { var match = partners.FirstOrDefault(p => string.Equals(p.PartnerName?.Trim(), name, StringComparison.OrdinalIgnoreCase) || string.Equals(p.Id, name, StringComparison.OrdinalIgnoreCase)); if (match is not null && !string.IsNullOrWhiteSpace(match.Id)) { partnerIdSet.Add(match.Id.Trim()); } } return partnerIdSet.OrderBy(x => x, StringComparer.Ordinal).ToList(); } /// /// 解析 Company(fl_partner.Id)下全部未删除门店 Id。 /// public static async Task> ResolveLocationIdsFromPartnerIdsAsync( ISqlSugarClient db, IReadOnlyList? partnerIds) { var ids = NormalizeIds(partnerIds); if (ids.Count == 0) { return new List(); } var result = new HashSet(StringComparer.Ordinal); foreach (var pid in ids) { var partner = await db.Queryable() .FirstAsync(x => !x.IsDeleted && x.Id == pid); if (partner is null) { continue; } var pName = partner.PartnerName?.Trim() ?? string.Empty; if (string.IsNullOrEmpty(pName)) { continue; } var locIds = await db.Queryable() .Where(x => !x.IsDeleted && x.Partner == pName) .Select(x => SqlFunc.ToString(x.Id)) .ToListAsync(); foreach (var lid in locIds.Where(x => !string.IsNullOrWhiteSpace(x))) { result.Add(lid.Trim()); } } return result.ToList(); } /// /// 根据已绑定门店反推适用的 Region Id(fl_group.Id)。 /// public static async Task> ResolveGroupIdsFromLocationIdsAsync( ISqlSugarClient db, IReadOnlyList locationIds) { var ids = NormalizeIds(locationIds); if (ids.Count == 0) { return new List(); } var guidList = ids.Where(x => Guid.TryParse(x, out _)).Select(Guid.Parse).ToList(); if (guidList.Count == 0) { return new List(); } var locs = await db.Queryable() .Where(x => !x.IsDeleted && guidList.Contains(x.Id)) .ToListAsync(); if (locs.Count == 0) { return new List(); } var partners = await db.Queryable() .Where(x => !x.IsDeleted) .ToListAsync(); var partnerNameToId = partners .Where(x => !string.IsNullOrWhiteSpace(x.PartnerName)) .GroupBy(x => x.PartnerName!.Trim(), StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Key, g => g.First().Id, StringComparer.OrdinalIgnoreCase); var groups = await db.Queryable() .Where(x => !x.IsDeleted) .ToListAsync(); var groupIdSet = new HashSet(StringComparer.Ordinal); foreach (var loc in locs) { var gName = loc.GroupName?.Trim(); var pName = loc.Partner?.Trim(); if (string.IsNullOrEmpty(gName) || string.IsNullOrEmpty(pName)) { continue; } if (!partnerNameToId.TryGetValue(pName, out var partnerId)) { continue; } var match = groups.FirstOrDefault(g => g.PartnerId == partnerId && string.Equals(g.GroupName?.Trim(), gName, StringComparison.OrdinalIgnoreCase)); if (match is not null && !string.IsNullOrWhiteSpace(match.Id)) { groupIdSet.Add(match.Id.Trim()); } } return groupIdSet.OrderBy(x => x, StringComparer.Ordinal).ToList(); } /// /// 解析 Region(fl_group.Id)下全部未删除门店 Id。 /// public static async Task> ResolveLocationIdsFromGroupIdsAsync( ISqlSugarClient db, IReadOnlyList? groupIds) { var ids = NormalizeIds(groupIds); if (ids.Count == 0) { return new List(); } var result = new HashSet(StringComparer.Ordinal); foreach (var gid in ids) { var g = await db.Queryable() .FirstAsync(x => !x.IsDeleted && x.Id == gid); if (g is null) { continue; } var partner = await db.Queryable() .FirstAsync(x => !x.IsDeleted && x.Id == g.PartnerId); var pName = partner?.PartnerName?.Trim() ?? string.Empty; var gName = g.GroupName?.Trim() ?? string.Empty; if (string.IsNullOrEmpty(pName) || string.IsNullOrEmpty(gName)) { continue; } var locIds = await db.Queryable() .Where(x => !x.IsDeleted && x.Partner == pName && x.GroupName == gName) .Select(x => SqlFunc.ToString(x.Id)) .ToListAsync(); foreach (var lid in locIds.Where(x => !string.IsNullOrWhiteSpace(x))) { result.Add(lid.Trim()); } } return result.ToList(); } /// /// 校验合并后的门店 Id 均存在。 /// public static async Task ValidateLocationIdsExistAsync(ISqlSugarClient db, IReadOnlyList locationIds) { var ids = NormalizeIds(locationIds); if (ids.Count == 0) { return; } foreach (var id in ids) { if (!Guid.TryParse(id, out _)) { throw new UserFriendlyException("门店Id格式不正确"); } } var guidList = ids.Select(Guid.Parse).ToList(); var existCount = await db.Queryable() .Where(x => !x.IsDeleted && guidList.Contains(x.Id)) .CountAsync(); if (existCount != ids.Count) { throw new UserFriendlyException("门店不存在"); } } public static List NormalizeIds(IReadOnlyList? raw) { return raw? .Where(x => !string.IsNullOrWhiteSpace(x)) .Select(x => x.Trim()) .Distinct(StringComparer.Ordinal) .ToList() ?? new List(); } }