diff --git a/src/Api/TakeoutSaaS.AdminApi/appsettings.Seed.Development.json b/src/Api/TakeoutSaaS.AdminApi/appsettings.Seed.Development.json index 7c4a6c2..a0c31a9 100644 --- a/src/Api/TakeoutSaaS.AdminApi/appsettings.Seed.Development.json +++ b/src/Api/TakeoutSaaS.AdminApi/appsettings.Seed.Development.json @@ -103,6 +103,7 @@ "merchant_category:delete", "store:create", "store:read", + "store:read:all", "store:update", "store:delete", "store-table-area:read", @@ -411,6 +412,7 @@ "merchant_category:delete", "store:create", "store:read", + "store:read:all", "store:update", "store:delete", "product:create", diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CalculateStoreFeeQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CalculateStoreFeeQueryHandler.cs index c8f7189..aa33124 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CalculateStoreFeeQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CalculateStoreFeeQueryHandler.cs @@ -1,4 +1,5 @@ using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Services; @@ -17,6 +18,7 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; public sealed class CalculateStoreFeeQueryHandler( IStoreRepository storeRepository, ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor, IStoreFeeCalculationService feeCalculationService) : IRequestHandler { @@ -24,7 +26,8 @@ public sealed class CalculateStoreFeeQueryHandler( public async Task Handle(CalculateStoreFeeQuery request, CancellationToken cancellationToken) { // 1. 校验门店存在 - var tenantId = tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken); if (store is null) { diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CheckStoreQualificationsQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CheckStoreQualificationsQueryHandler.cs index 11dad7b..2257e38 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CheckStoreQualificationsQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CheckStoreQualificationsQueryHandler.cs @@ -1,4 +1,5 @@ using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Domain.Stores.Enums; @@ -14,14 +15,16 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class CheckStoreQualificationsQueryHandler( IStoreRepository storeRepository, - ITenantProvider tenantProvider) + ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor) : IRequestHandler { /// public async Task Handle(CheckStoreQualificationsQuery request, CancellationToken cancellationToken) { // 1. 校验门店存在 - var tenantId = tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken); if (store is null) { diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CreateStoreCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CreateStoreCommandHandler.cs index 8c55355..7815e87 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CreateStoreCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/CreateStoreCommandHandler.cs @@ -1,8 +1,10 @@ using MediatR; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using TakeoutSaaS.Application.App.Stores; using TakeoutSaaS.Application.App.Stores.Commands; using TakeoutSaaS.Application.App.Stores.Dto; +using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Domain.Stores.Entities; using TakeoutSaaS.Domain.Stores.Enums; using TakeoutSaaS.Domain.Stores.Repositories; @@ -17,17 +19,30 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class CreateStoreCommandHandler( IStoreRepository storeRepository, + IMerchantRepository merchantRepository, ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor, ILogger logger) : IRequestHandler { /// public async Task Handle(CreateStoreCommand request, CancellationToken cancellationToken) { - // 1. 校验门店坐标唯一性(100 米内禁止重复) + // 1. 校验商户存在并解析租户 + var currentTenantId = tenantProvider.GetCurrentTenantId(); + var allowCrossTenant = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor); + var merchant = allowCrossTenant + ? await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) + : await merchantRepository.FindByIdAsync(request.MerchantId, currentTenantId, cancellationToken); + if (merchant == null) + { + throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); + } + var tenantId = merchant.TenantId; + + // 2. (空行后) 校验门店坐标唯一性(100 米内禁止重复) if (request.Longitude.HasValue && request.Latitude.HasValue) { - var tenantId = tenantProvider.GetCurrentTenantId(); var isDuplicate = await storeRepository.ExistsStoreWithinDistanceAsync( request.MerchantId, tenantId, @@ -41,16 +56,17 @@ public sealed class CreateStoreCommandHandler( } } - // 2. (空行后) 计算审核与经营状态 + // 3. (空行后) 计算审核与经营状态 var now = DateTime.UtcNow; var isSameEntity = request.OwnershipType == StoreOwnershipType.SameEntity; var auditStatus = isSameEntity ? StoreAuditStatus.Activated : StoreAuditStatus.Draft; var businessStatus = StoreBusinessStatus.Resting; DateTime? activatedAt = isSameEntity ? now : null; - // 3. (空行后) 构建实体 + // 4. (空行后) 构建实体 var store = new Store { + TenantId = tenantId, MerchantId = request.MerchantId, Code = request.Code.Trim(), Name = request.Name.Trim(), @@ -79,10 +95,14 @@ public sealed class CreateStoreCommandHandler( SupportsQueueing = request.SupportsQueueing }; - // 4. (空行后) 持久化并初始化费用配置 + // 5. (空行后) 持久化门店以获取标识 await storeRepository.AddStoreAsync(store, cancellationToken); + await storeRepository.SaveChangesAsync(cancellationToken); + + // 6. (空行后) 初始化费用配置 await storeRepository.AddStoreFeeAsync(new StoreFee { + TenantId = tenantId, StoreId = store.Id, MinimumOrderAmount = 0m, BaseDeliveryFee = 0m, @@ -92,7 +112,7 @@ public sealed class CreateStoreCommandHandler( await storeRepository.SaveChangesAsync(cancellationToken); logger.LogInformation("创建门店 {StoreId} - {StoreName}", store.Id, store.Name); - // 5. (空行后) 返回 DTO + // 7. (空行后) 返回 DTO return StoreMapping.ToDto(store); } } diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreByIdQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreByIdQueryHandler.cs index e8f0841..dda3076 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreByIdQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreByIdQueryHandler.cs @@ -1,4 +1,5 @@ using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; @@ -13,13 +14,15 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class GetStoreByIdQueryHandler( IStoreRepository storeRepository, - ITenantProvider tenantProvider) + ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor) : IRequestHandler { /// public async Task Handle(GetStoreByIdQuery request, CancellationToken cancellationToken) { - var tenantId = tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken); return store == null ? null : StoreMapping.ToDto(store); } diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreFeeQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreFeeQueryHandler.cs index 0ad2573..f73bcc3 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreFeeQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetStoreFeeQueryHandler.cs @@ -1,4 +1,5 @@ using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Domain.Stores.Entities; @@ -14,14 +15,16 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class GetStoreFeeQueryHandler( IStoreRepository storeRepository, - ITenantProvider tenantProvider) + ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor) : IRequestHandler { /// public async Task Handle(GetStoreFeeQuery request, CancellationToken cancellationToken) { // 1. 校验门店存在 - var tenantId = tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken); if (store is null) { diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreBusinessHoursQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreBusinessHoursQueryHandler.cs index f0f2c5d..76b6815 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreBusinessHoursQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreBusinessHoursQueryHandler.cs @@ -1,5 +1,6 @@ using System.Linq; using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Domain.Stores.Repositories; @@ -12,17 +13,20 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class ListStoreBusinessHoursQueryHandler( IStoreRepository storeRepository, - ITenantProvider tenantProvider) + ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor) : IRequestHandler> { private readonly IStoreRepository _storeRepository = storeRepository; private readonly ITenantProvider _tenantProvider = tenantProvider; + private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor; /// public async Task> Handle(ListStoreBusinessHoursQuery request, CancellationToken cancellationToken) { // 1. 查询时段列表 - var tenantId = _tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(_httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : _tenantProvider.GetCurrentTenantId(); var hours = await _storeRepository.GetBusinessHoursAsync(request.StoreId, tenantId, cancellationToken); // 2. 映射 DTO diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreDeliveryZonesQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreDeliveryZonesQueryHandler.cs index ffcc741..498b168 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreDeliveryZonesQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreDeliveryZonesQueryHandler.cs @@ -1,5 +1,6 @@ using System.Linq; using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Domain.Stores.Repositories; @@ -12,17 +13,20 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class ListStoreDeliveryZonesQueryHandler( IStoreRepository storeRepository, - ITenantProvider tenantProvider) + ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor) : IRequestHandler> { private readonly IStoreRepository _storeRepository = storeRepository; private readonly ITenantProvider _tenantProvider = tenantProvider; + private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor; /// public async Task> Handle(ListStoreDeliveryZonesQuery request, CancellationToken cancellationToken) { // 1. 查询配送区域 - var tenantId = _tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(_httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : _tenantProvider.GetCurrentTenantId(); var zones = await _storeRepository.GetDeliveryZonesAsync(request.StoreId, tenantId, cancellationToken); // 2. 映射 DTO diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreQualificationsQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreQualificationsQueryHandler.cs index 4f4ba93..38da278 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreQualificationsQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/ListStoreQualificationsQueryHandler.cs @@ -1,4 +1,5 @@ using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Domain.Stores.Repositories; @@ -13,14 +14,16 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class ListStoreQualificationsQueryHandler( IStoreRepository storeRepository, - ITenantProvider tenantProvider) + ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor) : IRequestHandler> { /// public async Task> Handle(ListStoreQualificationsQuery request, CancellationToken cancellationToken) { // 1. 校验门店存在 - var tenantId = tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken); if (store is null) { diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/SearchStoresQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/SearchStoresQueryHandler.cs index e94570c..72a9883 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/SearchStoresQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/SearchStoresQueryHandler.cs @@ -1,4 +1,5 @@ using MediatR; +using Microsoft.AspNetCore.Http; using TakeoutSaaS.Application.App.Stores; using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Queries; @@ -13,13 +14,15 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers; /// public sealed class SearchStoresQueryHandler( IStoreRepository storeRepository, - ITenantProvider tenantProvider) + ITenantProvider tenantProvider, + IHttpContextAccessor httpContextAccessor) : IRequestHandler> { /// public async Task> Handle(SearchStoresQuery request, CancellationToken cancellationToken) { - var tenantId = tenantProvider.GetCurrentTenantId(); + var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor); + var tenantId = ignoreTenantFilter ? 0 : tenantProvider.GetCurrentTenantId(); var stores = await storeRepository.SearchAsync( tenantId, request.MerchantId, @@ -28,6 +31,7 @@ public sealed class SearchStoresQueryHandler( request.BusinessStatus, request.OwnershipType, request.Keyword, + ignoreTenantFilter, cancellationToken); var sorted = ApplySorting(stores, request.SortBy, request.SortDescending); diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/StoreTenantAccess.cs b/src/Application/TakeoutSaaS.Application/App/Stores/StoreTenantAccess.cs new file mode 100644 index 0000000..f63f77c --- /dev/null +++ b/src/Application/TakeoutSaaS.Application/App/Stores/StoreTenantAccess.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Linq; + +namespace TakeoutSaaS.Application.App.Stores; + +internal static class StoreTenantAccess +{ + private const string PermissionClaimType = "permission"; + private const string ViewAllStoresPermission = "store:read:all"; + private static readonly string[] PlatformRoleCodes = + { + "super-admin", + "SUPER_ADMIN", + "PlatformAdmin", + "platform-admin" + }; + + public static bool ShouldIgnoreTenantFilter(IHttpContextAccessor httpContextAccessor) + { + var httpContext = httpContextAccessor.HttpContext; + if (httpContext == null) + { + return false; + } + + var user = httpContext.User; + if (user?.Identity?.IsAuthenticated != true) + { + return false; + } + + if (PlatformRoleCodes.Any(user.IsInRole)) + { + return true; + } + + var permissions = user.FindAll(PermissionClaimType) + .Select(c => c.Value?.Trim()) + .Where(value => !string.IsNullOrWhiteSpace(value)) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + + return permissions.Contains(ViewAllStoresPermission); + } +} diff --git a/src/Domain/TakeoutSaaS.Domain/Stores/Repositories/IStoreRepository.cs b/src/Domain/TakeoutSaaS.Domain/Stores/Repositories/IStoreRepository.cs index ea27fa9..9440775 100644 --- a/src/Domain/TakeoutSaaS.Domain/Stores/Repositories/IStoreRepository.cs +++ b/src/Domain/TakeoutSaaS.Domain/Stores/Repositories/IStoreRepository.cs @@ -29,6 +29,7 @@ public interface IStoreRepository StoreBusinessStatus? businessStatus, StoreOwnershipType? ownershipType, string? keyword, + bool ignoreTenantFilter = false, CancellationToken cancellationToken = default); /// diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs index 8e5f558..a4bf3fd 100644 --- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs +++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs @@ -19,9 +19,19 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos /// public Task FindByIdAsync(long storeId, long tenantId, CancellationToken cancellationToken = default) { - return context.Stores - .AsNoTracking() - .Where(x => x.TenantId == tenantId && x.Id == storeId) + var query = context.Stores.AsNoTracking(); + if (tenantId <= 0) + { + query = query.IgnoreQueryFilters() + .Where(x => x.DeletedAt == null); + } + else + { + query = query.Where(x => x.TenantId == tenantId); + } + + return query + .Where(x => x.Id == storeId) .FirstOrDefaultAsync(cancellationToken); } @@ -44,11 +54,19 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos StoreBusinessStatus? businessStatus, StoreOwnershipType? ownershipType, string? keyword, + bool ignoreTenantFilter = false, CancellationToken cancellationToken = default) { - var query = context.Stores - .AsNoTracking() - .Where(x => x.TenantId == tenantId); + var query = context.Stores.AsNoTracking(); + if (ignoreTenantFilter) + { + query = query.IgnoreQueryFilters() + .Where(x => x.DeletedAt == null); + } + else + { + query = query.Where(x => x.TenantId == tenantId); + } if (merchantId.HasValue) { @@ -153,9 +171,19 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos /// public async Task> GetBusinessHoursAsync(long storeId, long tenantId, CancellationToken cancellationToken = default) { - var hours = await context.StoreBusinessHours - .AsNoTracking() - .Where(x => x.TenantId == tenantId && x.StoreId == storeId) + var query = context.StoreBusinessHours.AsNoTracking(); + if (tenantId <= 0) + { + query = query.IgnoreQueryFilters() + .Where(x => x.DeletedAt == null); + } + else + { + query = query.Where(x => x.TenantId == tenantId); + } + + var hours = await query + .Where(x => x.StoreId == storeId) .OrderBy(x => x.DayOfWeek) .ThenBy(x => x.StartTime) .ToListAsync(cancellationToken); @@ -166,9 +194,19 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos /// public Task GetStoreFeeAsync(long storeId, long tenantId, CancellationToken cancellationToken = default) { - return context.StoreFees - .AsNoTracking() - .Where(x => x.TenantId == tenantId && x.StoreId == storeId) + var query = context.StoreFees.AsNoTracking(); + if (tenantId <= 0) + { + query = query.IgnoreQueryFilters() + .Where(x => x.DeletedAt == null); + } + else + { + query = query.Where(x => x.TenantId == tenantId); + } + + return query + .Where(x => x.StoreId == storeId) .FirstOrDefaultAsync(cancellationToken); } @@ -188,9 +226,19 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos /// public async Task> GetQualificationsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default) { - var qualifications = await context.StoreQualifications - .AsNoTracking() - .Where(x => x.TenantId == tenantId && x.StoreId == storeId) + var query = context.StoreQualifications.AsNoTracking(); + if (tenantId <= 0) + { + query = query.IgnoreQueryFilters() + .Where(x => x.DeletedAt == null); + } + else + { + query = query.Where(x => x.TenantId == tenantId); + } + + var qualifications = await query + .Where(x => x.StoreId == storeId) .OrderBy(x => x.SortOrder) .ThenBy(x => x.QualificationType) .ToListAsync(cancellationToken); @@ -259,9 +307,19 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos /// public async Task> GetDeliveryZonesAsync(long storeId, long tenantId, CancellationToken cancellationToken = default) { - var zones = await context.StoreDeliveryZones - .AsNoTracking() - .Where(x => x.TenantId == tenantId && x.StoreId == storeId) + var query = context.StoreDeliveryZones.AsNoTracking(); + if (tenantId <= 0) + { + query = query.IgnoreQueryFilters() + .Where(x => x.DeletedAt == null); + } + else + { + query = query.Where(x => x.TenantId == tenantId); + } + + var zones = await query + .Where(x => x.StoreId == storeId) .OrderBy(x => x.SortOrder) .ToListAsync(cancellationToken);