From 8139c08b353368d5b06307c40e6413b7df7d7734 Mon Sep 17 00:00:00 2001 From: MSuMshk <2039814060@qq.com> Date: Wed, 18 Feb 2026 17:25:34 +0800 Subject: [PATCH] fix(store): enforce UTC holiday dates and exclude deleted stores --- .../Controllers/StoreApiHelpers.cs | 3 +- .../App/Repositories/EfStoreRepository.cs | 37 ++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/Api/TakeoutSaaS.TenantApi/Controllers/StoreApiHelpers.cs b/src/Api/TakeoutSaaS.TenantApi/Controllers/StoreApiHelpers.cs index 2c7978f..082e1cb 100644 --- a/src/Api/TakeoutSaaS.TenantApi/Controllers/StoreApiHelpers.cs +++ b/src/Api/TakeoutSaaS.TenantApi/Controllers/StoreApiHelpers.cs @@ -95,7 +95,8 @@ internal static class StoreApiHelpers throw new BusinessException(ErrorCodes.BadRequest, $"{fieldName} 日期格式必须为 yyyy-MM-dd"); } - return parsed.Date; + // PostgreSQL timestamptz 仅接受 UTC,日期输入统一落盘为 UTC 零点。 + return DateTime.SpecifyKind(parsed.Date, DateTimeKind.Utc); } public static string ToDateOnly(DateTime value) diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs index a21d40a..3378273 100644 --- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs +++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfStoreRepository.cs @@ -33,7 +33,13 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos query = query.Where(x => x.TenantId == tenantId.Value); } - // 3. (空行后) 返回门店实体 + // 3. (空行后) 默认排除已删除门店(双保险) + if (!includeDeleted) + { + query = query.Where(x => x.DeletedAt == null); + } + + // 4. (空行后) 返回门店实体 return query .Where(x => x.Id == storeId) .FirstOrDefaultAsync(cancellationToken); @@ -44,7 +50,10 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos { return await context.Stores .AsNoTracking() - .Where(x => x.TenantId == tenantId && x.MerchantId == merchantId) + .Where(x => + x.TenantId == tenantId && + x.MerchantId == merchantId && + x.DeletedAt == null) .OrderBy(x => x.Name) .ToListAsync(cancellationToken); } @@ -81,31 +90,37 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos query = query.Where(x => x.MerchantId == merchantId.Value); } - // 4. (空行后) 可选过滤:状态 + // 4. (空行后) 默认排除已删除门店(双保险) + if (!includeDeleted) + { + query = query.Where(x => x.DeletedAt == null); + } + + // 5. (空行后) 可选过滤:状态 if (status.HasValue) { query = query.Where(x => x.Status == status.Value); } - // 5. (空行后) 可选过滤:审核状态 + // 6. (空行后) 可选过滤:审核状态 if (auditStatus.HasValue) { query = query.Where(x => x.AuditStatus == auditStatus.Value); } - // 6. (空行后) 可选过滤:经营状态 + // 7. (空行后) 可选过滤:经营状态 if (businessStatus.HasValue) { query = query.Where(x => x.BusinessStatus == businessStatus.Value); } - // 7. (空行后) 可选过滤:主体类型 + // 8. (空行后) 可选过滤:主体类型 if (ownershipType.HasValue) { query = query.Where(x => x.OwnershipType == ownershipType.Value); } - // 8. (空行后) 可选过滤:关键词 + // 9. (空行后) 可选过滤:关键词 if (!string.IsNullOrWhiteSpace(keyword)) { var trimmed = keyword.Trim(); @@ -115,7 +130,7 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos (x.Phone != null && x.Phone.Contains(trimmed))); } - // 9. (空行后) 查询并返回结果 + // 10. (空行后) 查询并返回结果 var stores = await query .OrderBy(x => x.Name) .ToListAsync(cancellationToken); @@ -142,6 +157,7 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos var coordinates = await context.Stores .AsNoTracking() .Where(x => x.TenantId == tenantId && x.MerchantId == merchantId) + .Where(x => x.DeletedAt == null) .Where(x => x.Longitude.HasValue && x.Latitude.HasValue) .Select(x => new { Longitude = x.Longitude!.Value, Latitude = x.Latitude!.Value }) .ToListAsync(cancellationToken); @@ -176,7 +192,10 @@ public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepos query = query.Where(x => x.TenantId == tenantId.Value); } - // 2. (空行后) 分组统计门店数量 + // 2. (空行后) 排除已删除门店 + query = query.Where(x => x.DeletedAt == null); + + // 3. (空行后) 分组统计门店数量 return await query .Where(x => merchantIds.Contains(x.MerchantId)) .GroupBy(x => x.MerchantId)