Files
TakeoutSaaS.AdminApi/src/Application/TakeoutSaaS.Application/App/Stores/Handlers/GetAvailablePickupSlotsQueryHandler.cs

88 lines
3.3 KiB
C#

using MediatR;
using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories;
namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// <summary>
/// 可用自提档期查询处理器。
/// </summary>
public sealed class GetAvailablePickupSlotsQueryHandler(
IStoreRepository storeRepository)
: IRequestHandler<GetAvailablePickupSlotsQuery, IReadOnlyList<StorePickupSlotDto>>
{
/// <inheritdoc />
public async Task<IReadOnlyList<StorePickupSlotDto>> Handle(GetAvailablePickupSlotsQuery request, CancellationToken cancellationToken)
{
// 1. 读取门店并解析租户
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return [];
}
var tenantId = store.TenantId;
var date = request.Date.Date;
// 2. (空行后) 读取配置
var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken);
var allowDays = setting?.AllowDaysAhead ?? 0;
var allowToday = setting?.AllowToday ?? false;
var defaultCutoff = setting?.DefaultCutoffMinutes ?? 30;
// 3. (空行后) 校验日期范围
if (!allowToday && date == DateTime.UtcNow.Date)
{
return [];
}
if (date > DateTime.UtcNow.Date.AddDays(allowDays))
{
return [];
}
// 4. (空行后) 读取档期
var slots = await storeRepository.GetPickupSlotsAsync(request.StoreId, tenantId, cancellationToken);
var weekday = (int)date.DayOfWeek;
weekday = weekday == 0 ? 7 : weekday;
var nowUtc = DateTime.UtcNow;
// 5. (空行后) 过滤可用
var available = slots
.Where(x => x.IsEnabled && ContainsDay(x.Weekdays, weekday))
.Select(slot =>
{
var cutoff = slot.CutoffMinutes == 0 ? defaultCutoff : slot.CutoffMinutes;
var slotStartUtc = date.Add(slot.StartTime);
// 判断截单
var cutoffTime = slotStartUtc.AddMinutes(-cutoff);
var isCutoff = nowUtc > cutoffTime;
var remaining = slot.Capacity - slot.ReservedCount;
return (slot, isCutoff, remaining);
})
.Where(x => !x.isCutoff && x.remaining > 0)
.Select(x => new StorePickupSlotDto
{
Id = x.slot.Id,
StoreId = x.slot.StoreId,
Name = x.slot.Name,
StartTime = x.slot.StartTime,
EndTime = x.slot.EndTime,
CutoffMinutes = x.slot.CutoffMinutes,
Capacity = x.slot.Capacity,
ReservedCount = x.slot.ReservedCount,
Weekdays = x.slot.Weekdays,
IsEnabled = x.slot.IsEnabled
})
.ToList();
return available;
}
private static bool ContainsDay(string weekdays, int target)
{
// 解析适用星期
var parts = weekdays.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
return parts.Any(p => int.TryParse(p, out var val) && val == target);
}
}