feat: 门店模块移除租户上下文依赖

This commit is contained in:
2026-01-29 14:27:01 +00:00
parent 010c2b7043
commit 71e5a9dc29
36 changed files with 280 additions and 209 deletions

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,28 +14,27 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class CreateStoreBusinessHourCommandHandler( public sealed class CreateStoreBusinessHourCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<CreateStoreBusinessHourCommandHandler> logger) ILogger<CreateStoreBusinessHourCommandHandler> logger)
: IRequestHandler<CreateStoreBusinessHourCommand, StoreBusinessHourDto> : IRequestHandler<CreateStoreBusinessHourCommand, StoreBusinessHourDto>
{ {
private readonly IStoreRepository _storeRepository = storeRepository; private readonly IStoreRepository _storeRepository = storeRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ILogger<CreateStoreBusinessHourCommandHandler> _logger = logger; private readonly ILogger<CreateStoreBusinessHourCommandHandler> _logger = logger;
/// <inheritdoc /> /// <inheritdoc />
public async Task<StoreBusinessHourDto> Handle(CreateStoreBusinessHourCommand request, CancellationToken cancellationToken) public async Task<StoreBusinessHourDto> Handle(CreateStoreBusinessHourCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = _tenantProvider.GetCurrentTenantId(); var store = await _storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await _storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. 构建实体 // 2. (空行后) 构建实体并写入租户
var hour = new StoreBusinessHour var hour = new StoreBusinessHour
{ {
TenantId = tenantId,
StoreId = request.StoreId, StoreId = request.StoreId,
DayOfWeek = request.DayOfWeek, DayOfWeek = request.DayOfWeek,
HourType = request.HourType, HourType = request.HourType,
@@ -46,12 +44,12 @@ public sealed class CreateStoreBusinessHourCommandHandler(
Notes = request.Notes?.Trim() Notes = request.Notes?.Trim()
}; };
// 3. 持久化 // 3. (空行后) 持久化
await _storeRepository.AddBusinessHoursAsync(new[] { hour }, cancellationToken); await _storeRepository.AddBusinessHoursAsync(new[] { hour }, cancellationToken);
await _storeRepository.SaveChangesAsync(cancellationToken); await _storeRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("创建营业时段 {BusinessHourId} 对应门店 {StoreId}", hour.Id, request.StoreId); _logger.LogInformation("创建营业时段 {BusinessHourId} 对应门店 {StoreId}", hour.Id, request.StoreId);
// 4. 返回 DTO // 4. (空行后) 返回 DTO
return StoreMapping.ToDto(hour); return StoreMapping.ToDto(hour);
} }
} }

View File

@@ -7,7 +7,6 @@ using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -17,7 +16,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
public sealed class CreateStoreEmployeeShiftCommandHandler( public sealed class CreateStoreEmployeeShiftCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
IMerchantRepository merchantRepository, IMerchantRepository merchantRepository,
ITenantProvider tenantProvider,
ILogger<CreateStoreEmployeeShiftCommandHandler> logger) ILogger<CreateStoreEmployeeShiftCommandHandler> logger)
: IRequestHandler<CreateStoreEmployeeShiftCommand, StoreEmployeeShiftDto> : IRequestHandler<CreateStoreEmployeeShiftCommand, StoreEmployeeShiftDto>
{ {
@@ -25,21 +23,21 @@ public sealed class CreateStoreEmployeeShiftCommandHandler(
public async Task<StoreEmployeeShiftDto> Handle(CreateStoreEmployeeShiftCommand request, CancellationToken cancellationToken) public async Task<StoreEmployeeShiftDto> Handle(CreateStoreEmployeeShiftCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. 校验员工归属与状态 // 2. (空行后) 校验员工归属与状态
var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken); var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken);
if (staff is null || (staff.StoreId.HasValue && staff.StoreId != request.StoreId)) if (staff is null || (staff.StoreId.HasValue && staff.StoreId != request.StoreId))
{ {
throw new BusinessException(ErrorCodes.ValidationFailed, "员工不存在或不属于该门店"); throw new BusinessException(ErrorCodes.ValidationFailed, "员工不存在或不属于该门店");
} }
// 3. 校验日期与冲突 // 3. (空行后) 校验日期与冲突
var from = request.ShiftDate.Date; var from = request.ShiftDate.Date;
var to = request.ShiftDate.Date; var to = request.ShiftDate.Date;
var shifts = await storeRepository.GetShiftsAsync(request.StoreId, tenantId, from, to, cancellationToken); var shifts = await storeRepository.GetShiftsAsync(request.StoreId, tenantId, from, to, cancellationToken);
@@ -49,9 +47,10 @@ public sealed class CreateStoreEmployeeShiftCommandHandler(
throw new BusinessException(ErrorCodes.Conflict, "该员工当日已存在排班"); throw new BusinessException(ErrorCodes.Conflict, "该员工当日已存在排班");
} }
// 4. 构建实体 // 4. (空行后) 构建实体并写入租户
var shift = new StoreEmployeeShift var shift = new StoreEmployeeShift
{ {
TenantId = tenantId,
StoreId = request.StoreId, StoreId = request.StoreId,
StaffId = request.StaffId, StaffId = request.StaffId,
ShiftDate = request.ShiftDate.Date, ShiftDate = request.ShiftDate.Date,
@@ -61,12 +60,12 @@ public sealed class CreateStoreEmployeeShiftCommandHandler(
Notes = request.Notes?.Trim() Notes = request.Notes?.Trim()
}; };
// 5. 持久化 // 5. (空行后) 持久化
await storeRepository.AddShiftsAsync(new[] { shift }, cancellationToken); await storeRepository.AddShiftsAsync(new[] { shift }, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("创建排班 {ShiftId} 员工 {StaffId} 门店 {StoreId}", shift.Id, shift.StaffId, shift.StoreId); logger.LogInformation("创建排班 {ShiftId} 员工 {StaffId} 门店 {StoreId}", shift.Id, shift.StaffId, shift.StoreId);
// 6. 返回 DTO // 6. (空行后) 返回 DTO
return StoreMapping.ToDto(shift); return StoreMapping.ToDto(shift);
} }
} }

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,7 +14,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class CreateStorePickupSlotCommandHandler( public sealed class CreateStorePickupSlotCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<CreateStorePickupSlotCommandHandler> logger) ILogger<CreateStorePickupSlotCommandHandler> logger)
: IRequestHandler<CreateStorePickupSlotCommand, StorePickupSlotDto> : IRequestHandler<CreateStorePickupSlotCommand, StorePickupSlotDto>
{ {
@@ -23,14 +21,14 @@ public sealed class CreateStorePickupSlotCommandHandler(
public async Task<StorePickupSlotDto> Handle(CreateStorePickupSlotCommand request, CancellationToken cancellationToken) public async Task<StorePickupSlotDto> Handle(CreateStorePickupSlotCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店 // 1. 校验门店
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. 新建档期 // 2. (空行后) 新建档期
var slot = new StorePickupSlot var slot = new StorePickupSlot
{ {
TenantId = tenantId, TenantId = tenantId,

View File

@@ -7,7 +7,6 @@ using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -16,7 +15,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class CreateStoreQualificationCommandHandler( public sealed class CreateStoreQualificationCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<CreateStoreQualificationCommandHandler> logger) ILogger<CreateStoreQualificationCommandHandler> logger)
: IRequestHandler<CreateStoreQualificationCommand, StoreQualificationDto> : IRequestHandler<CreateStoreQualificationCommand, StoreQualificationDto>
{ {
@@ -24,12 +22,12 @@ public sealed class CreateStoreQualificationCommandHandler(
public async Task<StoreQualificationDto> Handle(CreateStoreQualificationCommand request, CancellationToken cancellationToken) public async Task<StoreQualificationDto> Handle(CreateStoreQualificationCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. (空行后) 审核中门店禁止修改资质 // 2. (空行后) 审核中门店禁止修改资质
if (store.AuditStatus == StoreAuditStatus.Pending) if (store.AuditStatus == StoreAuditStatus.Pending)
@@ -49,6 +47,7 @@ public sealed class CreateStoreQualificationCommandHandler(
{ {
existing = new StoreQualification existing = new StoreQualification
{ {
TenantId = tenantId,
StoreId = request.StoreId, StoreId = request.StoreId,
QualificationType = request.QualificationType, QualificationType = request.QualificationType,
FileUrl = request.FileUrl.Trim(), FileUrl = request.FileUrl.Trim(),

View File

@@ -8,7 +8,6 @@ using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -18,7 +17,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
public sealed class CreateStoreStaffCommandHandler( public sealed class CreateStoreStaffCommandHandler(
IMerchantRepository merchantRepository, IMerchantRepository merchantRepository,
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<CreateStoreStaffCommandHandler> logger) ILogger<CreateStoreStaffCommandHandler> logger)
: IRequestHandler<CreateStoreStaffCommand, StoreStaffDto> : IRequestHandler<CreateStoreStaffCommand, StoreStaffDto>
{ {
@@ -26,16 +24,17 @@ public sealed class CreateStoreStaffCommandHandler(
public async Task<StoreStaffDto> Handle(CreateStoreStaffCommand request, CancellationToken cancellationToken) public async Task<StoreStaffDto> Handle(CreateStoreStaffCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店 // 1. 校验门店
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. 组装员工 // 2. (空行后) 组装员工并写入租户
var staff = new MerchantStaff var staff = new MerchantStaff
{ {
TenantId = tenantId,
MerchantId = store.MerchantId, MerchantId = store.MerchantId,
StoreId = request.StoreId, StoreId = request.StoreId,
Name = request.Name.Trim(), Name = request.Name.Trim(),

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,7 +14,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class CreateStoreTableAreaCommandHandler( public sealed class CreateStoreTableAreaCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<CreateStoreTableAreaCommandHandler> logger) ILogger<CreateStoreTableAreaCommandHandler> logger)
: IRequestHandler<CreateStoreTableAreaCommand, StoreTableAreaDto> : IRequestHandler<CreateStoreTableAreaCommand, StoreTableAreaDto>
{ {
@@ -23,14 +21,14 @@ public sealed class CreateStoreTableAreaCommandHandler(
public async Task<StoreTableAreaDto> Handle(CreateStoreTableAreaCommand request, CancellationToken cancellationToken) public async Task<StoreTableAreaDto> Handle(CreateStoreTableAreaCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. 校验区域名称唯一 // 2. (空行后) 校验区域名称唯一
var existingAreas = await storeRepository.GetTableAreasAsync(request.StoreId, tenantId, cancellationToken); var existingAreas = await storeRepository.GetTableAreasAsync(request.StoreId, tenantId, cancellationToken);
var hasDuplicate = existingAreas.Any(x => x.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase)); var hasDuplicate = existingAreas.Any(x => x.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
if (hasDuplicate) if (hasDuplicate)
@@ -38,21 +36,22 @@ public sealed class CreateStoreTableAreaCommandHandler(
throw new BusinessException(ErrorCodes.Conflict, "区域名称已存在"); throw new BusinessException(ErrorCodes.Conflict, "区域名称已存在");
} }
// 3. 构建实体 // 3. (空行后) 构建实体并写入租户
var area = new StoreTableArea var area = new StoreTableArea
{ {
TenantId = tenantId,
StoreId = request.StoreId, StoreId = request.StoreId,
Name = request.Name.Trim(), Name = request.Name.Trim(),
Description = request.Description?.Trim(), Description = request.Description?.Trim(),
SortOrder = request.SortOrder SortOrder = request.SortOrder
}; };
// 4. 持久化 // 4. (空行后) 持久化
await storeRepository.AddTableAreasAsync(new[] { area }, cancellationToken); await storeRepository.AddTableAreasAsync(new[] { area }, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("创建桌台区域 {AreaId} 对应门店 {StoreId}", area.Id, request.StoreId); logger.LogInformation("创建桌台区域 {AreaId} 对应门店 {StoreId}", area.Id, request.StoreId);
// 5. 返回 DTO // 5. (空行后) 返回 DTO
return StoreMapping.ToDto(area); return StoreMapping.ToDto(area);
} }
} }

View File

@@ -2,7 +2,6 @@ using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands; using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,32 +10,37 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStoreBusinessHourCommandHandler( public sealed class DeleteStoreBusinessHourCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<DeleteStoreBusinessHourCommandHandler> logger) ILogger<DeleteStoreBusinessHourCommandHandler> logger)
: IRequestHandler<DeleteStoreBusinessHourCommand, bool> : IRequestHandler<DeleteStoreBusinessHourCommand, bool>
{ {
private readonly IStoreRepository _storeRepository = storeRepository; private readonly IStoreRepository _storeRepository = storeRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ILogger<DeleteStoreBusinessHourCommandHandler> _logger = logger; private readonly ILogger<DeleteStoreBusinessHourCommandHandler> _logger = logger;
/// <inheritdoc /> /// <inheritdoc />
public async Task<bool> Handle(DeleteStoreBusinessHourCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStoreBusinessHourCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取时段 // 1. 读取门店并解析租户
var tenantId = _tenantProvider.GetCurrentTenantId(); var store = await _storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return false;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取时段
var existing = await _storeRepository.FindBusinessHourByIdAsync(request.BusinessHourId, tenantId, cancellationToken); var existing = await _storeRepository.FindBusinessHourByIdAsync(request.BusinessHourId, tenantId, cancellationToken);
if (existing is null) if (existing is null)
{ {
return false; return false;
} }
// 2. 校验门店归属 // 3. (空行后) 校验门店归属
if (existing.StoreId != request.StoreId) if (existing.StoreId != request.StoreId)
{ {
return false; return false;
} }
// 3. 删除 // 4. (空行后) 删除
await _storeRepository.DeleteBusinessHourAsync(request.BusinessHourId, tenantId, cancellationToken); await _storeRepository.DeleteBusinessHourAsync(request.BusinessHourId, tenantId, cancellationToken);
await _storeRepository.SaveChangesAsync(cancellationToken); await _storeRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("删除营业时段 {BusinessHourId} 对应门店 {StoreId}", request.BusinessHourId, request.StoreId); _logger.LogInformation("删除营业时段 {BusinessHourId} 对应门店 {StoreId}", request.BusinessHourId, request.StoreId);

View File

@@ -2,7 +2,6 @@ using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands; using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,26 +10,24 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStoreCommandHandler( public sealed class DeleteStoreCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<DeleteStoreCommandHandler> logger) ILogger<DeleteStoreCommandHandler> logger)
: IRequestHandler<DeleteStoreCommand, bool> : IRequestHandler<DeleteStoreCommand, bool>
{ {
private readonly IStoreRepository _storeRepository = storeRepository; private readonly IStoreRepository _storeRepository = storeRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ILogger<DeleteStoreCommandHandler> _logger = logger; private readonly ILogger<DeleteStoreCommandHandler> _logger = logger;
/// <inheritdoc /> /// <inheritdoc />
public async Task<bool> Handle(DeleteStoreCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStoreCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验存在性 // 1. 校验存在性(跨租户)
var tenantId = _tenantProvider.GetCurrentTenantId(); var existing = await _storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var existing = await _storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (existing == null) if (existing == null)
{ {
return false; return false;
} }
var tenantId = existing.TenantId;
// 2. 删除 // 2. (空行后) 删除
await _storeRepository.DeleteStoreAsync(request.StoreId, tenantId, cancellationToken); await _storeRepository.DeleteStoreAsync(request.StoreId, tenantId, cancellationToken);
await _storeRepository.SaveChangesAsync(cancellationToken); await _storeRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("删除门店 {StoreId}", request.StoreId); _logger.LogInformation("删除门店 {StoreId}", request.StoreId);

View File

@@ -2,7 +2,6 @@ using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands; using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,22 +10,28 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStoreEmployeeShiftCommandHandler( public sealed class DeleteStoreEmployeeShiftCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<DeleteStoreEmployeeShiftCommandHandler> logger) ILogger<DeleteStoreEmployeeShiftCommandHandler> logger)
: IRequestHandler<DeleteStoreEmployeeShiftCommand, bool> : IRequestHandler<DeleteStoreEmployeeShiftCommand, bool>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<bool> Handle(DeleteStoreEmployeeShiftCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStoreEmployeeShiftCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取排班 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return false;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取排班
var shift = await storeRepository.FindShiftByIdAsync(request.ShiftId, tenantId, cancellationToken); var shift = await storeRepository.FindShiftByIdAsync(request.ShiftId, tenantId, cancellationToken);
if (shift is null || shift.StoreId != request.StoreId) if (shift is null || shift.StoreId != request.StoreId)
{ {
return false; return false;
} }
// 2. 删除 // 3. (空行后) 删除
await storeRepository.DeleteShiftAsync(request.ShiftId, tenantId, cancellationToken); await storeRepository.DeleteShiftAsync(request.ShiftId, tenantId, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("删除排班 {ShiftId} 门店 {StoreId}", request.ShiftId, request.StoreId); logger.LogInformation("删除排班 {ShiftId} 门店 {StoreId}", request.ShiftId, request.StoreId);

View File

@@ -2,7 +2,6 @@ using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands; using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,15 +10,28 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStorePickupSlotCommandHandler( public sealed class DeleteStorePickupSlotCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<DeleteStorePickupSlotCommandHandler> logger) ILogger<DeleteStorePickupSlotCommandHandler> logger)
: IRequestHandler<DeleteStorePickupSlotCommand, bool> : IRequestHandler<DeleteStorePickupSlotCommand, bool>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<bool> Handle(DeleteStorePickupSlotCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStorePickupSlotCommand request, CancellationToken cancellationToken)
{ {
// 1. 删除档期 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return false;
}
var tenantId = store.TenantId;
// 2. (空行后) 校验档期归属
var slot = await storeRepository.FindPickupSlotByIdAsync(request.SlotId, tenantId, cancellationToken);
if (slot is null || slot.StoreId != request.StoreId)
{
return false;
}
// 3. (空行后) 删除档期
await storeRepository.DeletePickupSlotAsync(request.SlotId, tenantId, cancellationToken); await storeRepository.DeletePickupSlotAsync(request.SlotId, tenantId, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("删除自提档期 {SlotId}", request.SlotId); logger.LogInformation("删除自提档期 {SlotId}", request.SlotId);

View File

@@ -5,7 +5,6 @@ using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -14,7 +13,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStoreQualificationCommandHandler( public sealed class DeleteStoreQualificationCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<DeleteStoreQualificationCommandHandler> logger) ILogger<DeleteStoreQualificationCommandHandler> logger)
: IRequestHandler<DeleteStoreQualificationCommand, bool> : IRequestHandler<DeleteStoreQualificationCommand, bool>
{ {
@@ -22,12 +20,12 @@ public sealed class DeleteStoreQualificationCommandHandler(
public async Task<bool> Handle(DeleteStoreQualificationCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStoreQualificationCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. (空行后) 审核中门店禁止删除资质 // 2. (空行后) 审核中门店禁止删除资质
if (store.AuditStatus == StoreAuditStatus.Pending) if (store.AuditStatus == StoreAuditStatus.Pending)

View File

@@ -2,7 +2,7 @@ using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands; using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy; using TakeoutSaaS.Domain.Stores.Repositories;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,21 +11,29 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStoreStaffCommandHandler( public sealed class DeleteStoreStaffCommandHandler(
IMerchantRepository merchantRepository, IMerchantRepository merchantRepository,
ITenantProvider tenantProvider, IStoreRepository storeRepository,
ILogger<DeleteStoreStaffCommandHandler> logger) ILogger<DeleteStoreStaffCommandHandler> logger)
: IRequestHandler<DeleteStoreStaffCommand, bool> : IRequestHandler<DeleteStoreStaffCommand, bool>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<bool> Handle(DeleteStoreStaffCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStoreStaffCommand request, CancellationToken cancellationToken)
{ {
var tenantId = tenantProvider.GetCurrentTenantId(); // 1. 读取门店并解析租户
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return false;
}
var tenantId = store.TenantId;
// 2. (空行后) 校验员工归属
var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken); var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken);
if (staff is null || staff.StoreId != request.StoreId) if (staff is null || staff.StoreId != request.StoreId)
{ {
return false; return false;
} }
// 逻辑删除未定义,直接物理删除 // 3. (空行后) 逻辑删除未定义,直接物理删除
await merchantRepository.DeleteStaffAsync(staff.Id, tenantId, cancellationToken); await merchantRepository.DeleteStaffAsync(staff.Id, tenantId, cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken); await merchantRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("删除门店员工 {StaffId} 门店 {StoreId}", request.StaffId, request.StoreId); logger.LogInformation("删除门店员工 {StaffId} 门店 {StoreId}", request.StaffId, request.StoreId);

View File

@@ -4,7 +4,6 @@ using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -13,28 +12,34 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStoreTableAreaCommandHandler( public sealed class DeleteStoreTableAreaCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<DeleteStoreTableAreaCommandHandler> logger) ILogger<DeleteStoreTableAreaCommandHandler> logger)
: IRequestHandler<DeleteStoreTableAreaCommand, bool> : IRequestHandler<DeleteStoreTableAreaCommand, bool>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<bool> Handle(DeleteStoreTableAreaCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStoreTableAreaCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取区域 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return false;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取区域
var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId, tenantId, cancellationToken); var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId, tenantId, cancellationToken);
if (area is null) if (area is null)
{ {
return false; return false;
} }
// 2. 校验门店归属 // 3. (空行后) 校验门店归属
if (area.StoreId != request.StoreId) if (area.StoreId != request.StoreId)
{ {
return false; return false;
} }
// 3. 校验区域下无桌码 // 4. (空行后) 校验区域下无桌码
var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken); var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken);
var hasTable = tables.Any(x => x.AreaId == request.AreaId); var hasTable = tables.Any(x => x.AreaId == request.AreaId);
if (hasTable) if (hasTable)
@@ -42,7 +47,7 @@ public sealed class DeleteStoreTableAreaCommandHandler(
throw new BusinessException(ErrorCodes.Conflict, "区域下仍有桌码,无法删除"); throw new BusinessException(ErrorCodes.Conflict, "区域下仍有桌码,无法删除");
} }
// 4. 删除 // 5. (空行后) 删除
await storeRepository.DeleteTableAreaAsync(request.AreaId, tenantId, cancellationToken); await storeRepository.DeleteTableAreaAsync(request.AreaId, tenantId, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("删除桌台区域 {AreaId} 对应门店 {StoreId}", request.AreaId, request.StoreId); logger.LogInformation("删除桌台区域 {AreaId} 对应门店 {StoreId}", request.AreaId, request.StoreId);

View File

@@ -2,7 +2,6 @@ using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands; using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,22 +10,28 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class DeleteStoreTableCommandHandler( public sealed class DeleteStoreTableCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<DeleteStoreTableCommandHandler> logger) ILogger<DeleteStoreTableCommandHandler> logger)
: IRequestHandler<DeleteStoreTableCommand, bool> : IRequestHandler<DeleteStoreTableCommand, bool>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<bool> Handle(DeleteStoreTableCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(DeleteStoreTableCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取桌码 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return false;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取桌码
var table = await storeRepository.FindTableByIdAsync(request.TableId, tenantId, cancellationToken); var table = await storeRepository.FindTableByIdAsync(request.TableId, tenantId, cancellationToken);
if (table is null || table.StoreId != request.StoreId) if (table is null || table.StoreId != request.StoreId)
{ {
return false; return false;
} }
// 2. 删除 // 3. (空行后) 删除
await storeRepository.DeleteTableAsync(request.TableId, tenantId, cancellationToken); await storeRepository.DeleteTableAsync(request.TableId, tenantId, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("删除桌码 {TableId} 对应门店 {StoreId}", request.TableId, request.StoreId); logger.LogInformation("删除桌码 {TableId} 对应门店 {StoreId}", request.TableId, request.StoreId);

View File

@@ -7,7 +7,6 @@ using QRCoder;
using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -16,7 +15,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class ExportStoreTableQRCodesQueryHandler( public sealed class ExportStoreTableQRCodesQueryHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<ExportStoreTableQRCodesQueryHandler> logger) ILogger<ExportStoreTableQRCodesQueryHandler> logger)
: IRequestHandler<ExportStoreTableQRCodesQuery, StoreTableExportResult?> : IRequestHandler<ExportStoreTableQRCodesQuery, StoreTableExportResult?>
{ {
@@ -24,14 +22,14 @@ public sealed class ExportStoreTableQRCodesQueryHandler(
public async Task<StoreTableExportResult?> Handle(ExportStoreTableQRCodesQuery request, CancellationToken cancellationToken) public async Task<StoreTableExportResult?> Handle(ExportStoreTableQRCodesQuery request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
return null; return null;
} }
var tenantId = store.TenantId;
// 2. 获取桌码列表 // 2. (空行后) 获取桌码列表
var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken); var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken);
if (request.AreaId.HasValue) if (request.AreaId.HasValue)
{ {

View File

@@ -7,7 +7,6 @@ using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -16,7 +15,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class GenerateStoreTablesCommandHandler( public sealed class GenerateStoreTablesCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<GenerateStoreTablesCommandHandler> logger) ILogger<GenerateStoreTablesCommandHandler> logger)
: IRequestHandler<GenerateStoreTablesCommand, IReadOnlyList<StoreTableDto>> : IRequestHandler<GenerateStoreTablesCommand, IReadOnlyList<StoreTableDto>>
{ {
@@ -24,14 +22,14 @@ public sealed class GenerateStoreTablesCommandHandler(
public async Task<IReadOnlyList<StoreTableDto>> Handle(GenerateStoreTablesCommand request, CancellationToken cancellationToken) public async Task<IReadOnlyList<StoreTableDto>> Handle(GenerateStoreTablesCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. 校验区域归属 // 2. (空行后) 校验区域归属
if (request.AreaId.HasValue) if (request.AreaId.HasValue)
{ {
var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId.Value, tenantId, cancellationToken); var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId.Value, tenantId, cancellationToken);
@@ -41,7 +39,7 @@ public sealed class GenerateStoreTablesCommandHandler(
} }
} }
// 3. 校验桌码唯一性 // 3. (空行后) 校验桌码唯一性
var existingTables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken); var existingTables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken);
var newCodes = Enumerable.Range(request.StartNumber, request.Count) var newCodes = Enumerable.Range(request.StartNumber, request.Count)
.Select(i => $"{request.TableCodePrefix.Trim()}{i}") .Select(i => $"{request.TableCodePrefix.Trim()}{i}")
@@ -52,9 +50,10 @@ public sealed class GenerateStoreTablesCommandHandler(
throw new BusinessException(ErrorCodes.Conflict, "桌码已存在,生成失败"); throw new BusinessException(ErrorCodes.Conflict, "桌码已存在,生成失败");
} }
// 4. 构建实体 // 4. (空行后) 构建实体并写入租户
var tables = newCodes.Select(code => new StoreTable var tables = newCodes.Select(code => new StoreTable
{ {
TenantId = tenantId,
StoreId = request.StoreId, StoreId = request.StoreId,
AreaId = request.AreaId, AreaId = request.AreaId,
TableCode = code, TableCode = code,
@@ -62,12 +61,12 @@ public sealed class GenerateStoreTablesCommandHandler(
Tags = request.Tags?.Trim() Tags = request.Tags?.Trim()
}).ToList(); }).ToList();
// 5. 持久化 // 5. (空行后) 持久化
await storeRepository.AddTablesAsync(tables, cancellationToken); await storeRepository.AddTablesAsync(tables, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("批量创建桌码 {Count} 条 对应门店 {StoreId}", tables.Count, request.StoreId); logger.LogInformation("批量创建桌码 {Count} 条 对应门店 {StoreId}", tables.Count, request.StoreId);
// 6. 返回 DTO // 6. (空行后) 返回 DTO
return tables.Select(StoreMapping.ToDto).ToList(); return tables.Select(StoreMapping.ToDto).ToList();
} }
} }

View File

@@ -2,7 +2,6 @@ using MediatR;
using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -10,22 +9,27 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// 可用自提档期查询处理器。 /// 可用自提档期查询处理器。
/// </summary> /// </summary>
public sealed class GetAvailablePickupSlotsQueryHandler( public sealed class GetAvailablePickupSlotsQueryHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository)
ITenantProvider tenantProvider)
: IRequestHandler<GetAvailablePickupSlotsQuery, IReadOnlyList<StorePickupSlotDto>> : IRequestHandler<GetAvailablePickupSlotsQuery, IReadOnlyList<StorePickupSlotDto>>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<IReadOnlyList<StorePickupSlotDto>> Handle(GetAvailablePickupSlotsQuery request, CancellationToken cancellationToken) public async Task<IReadOnlyList<StorePickupSlotDto>> Handle(GetAvailablePickupSlotsQuery request, CancellationToken cancellationToken)
{ {
var tenantId = tenantProvider.GetCurrentTenantId(); // 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; var date = request.Date.Date;
// 1. 读取配置 // 2. (空行后) 读取配置
var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken); var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken);
var allowDays = setting?.AllowDaysAhead ?? 0; var allowDays = setting?.AllowDaysAhead ?? 0;
var allowToday = setting?.AllowToday ?? false; var allowToday = setting?.AllowToday ?? false;
var defaultCutoff = setting?.DefaultCutoffMinutes ?? 30; var defaultCutoff = setting?.DefaultCutoffMinutes ?? 30;
// 2. 校验日期范围 // 3. (空行后) 校验日期范围
if (!allowToday && date == DateTime.UtcNow.Date) if (!allowToday && date == DateTime.UtcNow.Date)
{ {
return []; return [];
@@ -36,13 +40,13 @@ public sealed class GetAvailablePickupSlotsQueryHandler(
return []; return [];
} }
// 3. 读取档期 // 4. (空行后) 读取档期
var slots = await storeRepository.GetPickupSlotsAsync(request.StoreId, tenantId, cancellationToken); var slots = await storeRepository.GetPickupSlotsAsync(request.StoreId, tenantId, cancellationToken);
var weekday = (int)date.DayOfWeek; var weekday = (int)date.DayOfWeek;
weekday = weekday == 0 ? 7 : weekday; weekday = weekday == 0 ? 7 : weekday;
var nowUtc = DateTime.UtcNow; var nowUtc = DateTime.UtcNow;
// 4. 过滤可用 // 5. (空行后) 过滤可用
var available = slots var available = slots
.Where(x => x.IsEnabled && ContainsDay(x.Weekdays, weekday)) .Where(x => x.IsEnabled && ContainsDay(x.Weekdays, weekday))
.Select(slot => .Select(slot =>

View File

@@ -2,7 +2,6 @@ using MediatR;
using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -10,20 +9,28 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// 获取自提配置处理器。 /// 获取自提配置处理器。
/// </summary> /// </summary>
public sealed class GetStorePickupSettingQueryHandler( public sealed class GetStorePickupSettingQueryHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository)
ITenantProvider tenantProvider)
: IRequestHandler<GetStorePickupSettingQuery, StorePickupSettingDto?> : IRequestHandler<GetStorePickupSettingQuery, StorePickupSettingDto?>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<StorePickupSettingDto?> Handle(GetStorePickupSettingQuery request, CancellationToken cancellationToken) public async Task<StorePickupSettingDto?> Handle(GetStorePickupSettingQuery request, CancellationToken cancellationToken)
{ {
var tenantId = tenantProvider.GetCurrentTenantId(); // 1. 读取门店并解析租户
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return null;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取配置
var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken); var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken);
if (setting is null) if (setting is null)
{ {
return null; return null;
} }
// 3. (空行后) 返回 DTO
return new StorePickupSettingDto return new StorePickupSettingDto
{ {
Id = setting.Id, Id = setting.Id,

View File

@@ -5,7 +5,6 @@ using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -14,7 +13,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class GetStoreTableContextQueryHandler( public sealed class GetStoreTableContextQueryHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<GetStoreTableContextQueryHandler> logger) ILogger<GetStoreTableContextQueryHandler> logger)
: IRequestHandler<GetStoreTableContextQuery, StoreTableContextDto?> : IRequestHandler<GetStoreTableContextQuery, StoreTableContextDto?>
{ {
@@ -22,7 +20,7 @@ public sealed class GetStoreTableContextQueryHandler(
public async Task<StoreTableContextDto?> Handle(GetStoreTableContextQuery request, CancellationToken cancellationToken) public async Task<StoreTableContextDto?> Handle(GetStoreTableContextQuery request, CancellationToken cancellationToken)
{ {
// 1. 查询桌码 // 1. 查询桌码
var tenantId = tenantProvider.GetCurrentTenantId(); var tenantId = request.TenantId;
var table = await storeRepository.FindTableByCodeAsync(request.TableCode, tenantId, cancellationToken); var table = await storeRepository.FindTableByCodeAsync(request.TableCode, tenantId, cancellationToken);
if (table is null) if (table is null)
{ {

View File

@@ -3,7 +3,6 @@ using MediatR;
using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,8 +10,7 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// 排班列表查询处理器。 /// 排班列表查询处理器。
/// </summary> /// </summary>
public sealed class ListStoreEmployeeShiftsQueryHandler( public sealed class ListStoreEmployeeShiftsQueryHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository)
ITenantProvider tenantProvider)
: IRequestHandler<ListStoreEmployeeShiftsQuery, IReadOnlyList<StoreEmployeeShiftDto>> : IRequestHandler<ListStoreEmployeeShiftsQuery, IReadOnlyList<StoreEmployeeShiftDto>>
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -21,9 +19,14 @@ public sealed class ListStoreEmployeeShiftsQueryHandler(
// 1. 时间范围 // 1. 时间范围
var from = request.From ?? DateTime.UtcNow.Date; var from = request.From ?? DateTime.UtcNow.Date;
var to = request.To ?? from.AddDays(7); var to = request.To ?? from.AddDays(7);
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return [];
}
var tenantId = store.TenantId;
// 2. 查询排班 // 2. (空行后) 查询排班
var shifts = await storeRepository.GetShiftsAsync(request.StoreId, tenantId, from, to, cancellationToken); var shifts = await storeRepository.GetShiftsAsync(request.StoreId, tenantId, from, to, cancellationToken);
if (request.StaffId.HasValue) if (request.StaffId.HasValue)
@@ -31,7 +34,7 @@ public sealed class ListStoreEmployeeShiftsQueryHandler(
shifts = shifts.Where(x => x.StaffId == request.StaffId.Value).ToList(); shifts = shifts.Where(x => x.StaffId == request.StaffId.Value).ToList();
} }
// 3. 映射 DTO // 3. (空行后) 映射 DTO
return shifts.Select(StoreMapping.ToDto).ToList(); return shifts.Select(StoreMapping.ToDto).ToList();
} }
} }

View File

@@ -2,7 +2,6 @@ using MediatR;
using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -10,14 +9,21 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// 自提档期列表查询处理器。 /// 自提档期列表查询处理器。
/// </summary> /// </summary>
public sealed class ListStorePickupSlotsQueryHandler( public sealed class ListStorePickupSlotsQueryHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository)
ITenantProvider tenantProvider)
: IRequestHandler<ListStorePickupSlotsQuery, IReadOnlyList<StorePickupSlotDto>> : IRequestHandler<ListStorePickupSlotsQuery, IReadOnlyList<StorePickupSlotDto>>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<IReadOnlyList<StorePickupSlotDto>> Handle(ListStorePickupSlotsQuery request, CancellationToken cancellationToken) public async Task<IReadOnlyList<StorePickupSlotDto>> Handle(ListStorePickupSlotsQuery request, CancellationToken cancellationToken)
{ {
var tenantId = tenantProvider.GetCurrentTenantId(); // 1. 读取门店并解析租户
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return [];
}
var tenantId = store.TenantId;
// 2. (空行后) 查询档期列表
var slots = await storeRepository.GetPickupSlotsAsync(request.StoreId, tenantId, cancellationToken); var slots = await storeRepository.GetPickupSlotsAsync(request.StoreId, tenantId, cancellationToken);
return slots return slots
.Select(x => new StorePickupSlotDto .Select(x => new StorePickupSlotDto

View File

@@ -4,7 +4,6 @@ using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -13,22 +12,21 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class ListStoreStaffQueryHandler( public sealed class ListStoreStaffQueryHandler(
IMerchantRepository merchantRepository, IMerchantRepository merchantRepository,
IStoreRepository storeRepository, IStoreRepository storeRepository)
ITenantProvider tenantProvider)
: IRequestHandler<ListStoreStaffQuery, IReadOnlyList<StoreStaffDto>> : IRequestHandler<ListStoreStaffQuery, IReadOnlyList<StoreStaffDto>>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<IReadOnlyList<StoreStaffDto>> Handle(ListStoreStaffQuery request, CancellationToken cancellationToken) public async Task<IReadOnlyList<StoreStaffDto>> Handle(ListStoreStaffQuery request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
return []; return [];
} }
var tenantId = store.TenantId;
// 2. 查询员工 // 2. (空行后) 查询员工
var staffs = await merchantRepository.GetStaffByStoreAsync(request.StoreId, tenantId, cancellationToken); var staffs = await merchantRepository.GetStaffByStoreAsync(request.StoreId, tenantId, cancellationToken);
if (request.RoleType.HasValue) if (request.RoleType.HasValue)
@@ -41,7 +39,7 @@ public sealed class ListStoreStaffQueryHandler(
staffs = staffs.Where(x => x.Status == request.Status.Value).ToList(); staffs = staffs.Where(x => x.Status == request.Status.Value).ToList();
} }
// 3. 映射 DTO // 3. (空行后) 映射 DTO
return staffs.Select(StoreMapping.ToDto).ToList(); return staffs.Select(StoreMapping.ToDto).ToList();
} }
} }

View File

@@ -3,24 +3,30 @@ using MediatR;
using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// <summary> /// <summary>
/// 桌台区域列表查询处理器。 /// 桌台区域列表查询处理器。
/// </summary> /// </summary>
public sealed class ListStoreTableAreasQueryHandler(IStoreRepository storeRepository, ITenantProvider tenantProvider) public sealed class ListStoreTableAreasQueryHandler(IStoreRepository storeRepository)
: IRequestHandler<ListStoreTableAreasQuery, IReadOnlyList<StoreTableAreaDto>> : IRequestHandler<ListStoreTableAreasQuery, IReadOnlyList<StoreTableAreaDto>>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<IReadOnlyList<StoreTableAreaDto>> Handle(ListStoreTableAreasQuery request, CancellationToken cancellationToken) public async Task<IReadOnlyList<StoreTableAreaDto>> Handle(ListStoreTableAreasQuery request, CancellationToken cancellationToken)
{ {
// 1. 查询区域列表 // 1. 查询门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return [];
}
var tenantId = store.TenantId;
// 2. (空行后) 查询区域列表
var areas = await storeRepository.GetTableAreasAsync(request.StoreId, tenantId, cancellationToken); var areas = await storeRepository.GetTableAreasAsync(request.StoreId, tenantId, cancellationToken);
// 2. 映射 DTO // 3. (空行后) 映射 DTO
return areas.Select(StoreMapping.ToDto).ToList(); return areas.Select(StoreMapping.ToDto).ToList();
} }
} }

View File

@@ -3,7 +3,6 @@ using MediatR;
using TakeoutSaaS.Application.App.Stores.Dto; using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Queries; using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -11,18 +10,24 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// 桌码列表查询处理器。 /// 桌码列表查询处理器。
/// </summary> /// </summary>
public sealed class ListStoreTablesQueryHandler( public sealed class ListStoreTablesQueryHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository)
ITenantProvider tenantProvider)
: IRequestHandler<ListStoreTablesQuery, IReadOnlyList<StoreTableDto>> : IRequestHandler<ListStoreTablesQuery, IReadOnlyList<StoreTableDto>>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<IReadOnlyList<StoreTableDto>> Handle(ListStoreTablesQuery request, CancellationToken cancellationToken) public async Task<IReadOnlyList<StoreTableDto>> Handle(ListStoreTablesQuery request, CancellationToken cancellationToken)
{ {
// 1. 查询桌码列表 // 1. 查询门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return [];
}
var tenantId = store.TenantId;
// 2. (空行后) 查询桌码列表
var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken); var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken);
// 2. 过滤 // 3. (空行后) 过滤
if (request.AreaId.HasValue) if (request.AreaId.HasValue)
{ {
tables = tables.Where(x => x.AreaId == request.AreaId.Value).ToList(); tables = tables.Where(x => x.AreaId == request.AreaId.Value).ToList();
@@ -33,7 +38,7 @@ public sealed class ListStoreTablesQueryHandler(
tables = tables.Where(x => x.Status == request.Status.Value).ToList(); tables = tables.Where(x => x.Status == request.Status.Value).ToList();
} }
// 3. 映射 DTO // 4. (空行后) 映射 DTO
return tables.Select(StoreMapping.ToDto).ToList(); return tables.Select(StoreMapping.ToDto).ToList();
} }
} }

View File

@@ -8,7 +8,6 @@ using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Security; using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -17,7 +16,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class SubmitStoreAuditCommandHandler( public sealed class SubmitStoreAuditCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ICurrentUserAccessor currentUserAccessor, ICurrentUserAccessor currentUserAccessor,
IMediator mediator, IMediator mediator,
ILogger<SubmitStoreAuditCommandHandler> logger) ILogger<SubmitStoreAuditCommandHandler> logger)
@@ -27,12 +25,12 @@ public sealed class SubmitStoreAuditCommandHandler(
public async Task<bool> Handle(SubmitStoreAuditCommand request, CancellationToken cancellationToken) public async Task<bool> Handle(SubmitStoreAuditCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
if (store.AuditStatus is not StoreAuditStatus.Draft and not StoreAuditStatus.Rejected) if (store.AuditStatus is not StoreAuditStatus.Draft and not StoreAuditStatus.Rejected)
{ {
@@ -53,6 +51,7 @@ public sealed class SubmitStoreAuditCommandHandler(
await storeRepository.UpdateStoreAsync(store, cancellationToken); await storeRepository.UpdateStoreAsync(store, cancellationToken);
await storeRepository.AddAuditRecordAsync(new StoreAuditRecord await storeRepository.AddAuditRecordAsync(new StoreAuditRecord
{ {
TenantId = tenantId,
StoreId = store.Id, StoreId = store.Id,
Action = StoreAuditAction.AutoActivate, Action = StoreAuditAction.AutoActivate,
PreviousStatus = previousStatus, PreviousStatus = previousStatus,
@@ -87,6 +86,7 @@ public sealed class SubmitStoreAuditCommandHandler(
await storeRepository.UpdateStoreAsync(store, cancellationToken); await storeRepository.UpdateStoreAsync(store, cancellationToken);
await storeRepository.AddAuditRecordAsync(new StoreAuditRecord await storeRepository.AddAuditRecordAsync(new StoreAuditRecord
{ {
TenantId = tenantId,
StoreId = store.Id, StoreId = store.Id,
Action = action, Action = action,
PreviousStatus = previous, PreviousStatus = previous,

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,7 +14,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class ToggleBusinessStatusCommandHandler( public sealed class ToggleBusinessStatusCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<ToggleBusinessStatusCommandHandler> logger) ILogger<ToggleBusinessStatusCommandHandler> logger)
: IRequestHandler<ToggleBusinessStatusCommand, StoreDto> : IRequestHandler<ToggleBusinessStatusCommand, StoreDto>
{ {
@@ -23,8 +21,7 @@ public sealed class ToggleBusinessStatusCommandHandler(
public async Task<StoreDto> Handle(ToggleBusinessStatusCommand request, CancellationToken cancellationToken) public async Task<StoreDto> Handle(ToggleBusinessStatusCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,32 +14,37 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class UpdateStoreBusinessHourCommandHandler( public sealed class UpdateStoreBusinessHourCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<UpdateStoreBusinessHourCommandHandler> logger) ILogger<UpdateStoreBusinessHourCommandHandler> logger)
: IRequestHandler<UpdateStoreBusinessHourCommand, StoreBusinessHourDto?> : IRequestHandler<UpdateStoreBusinessHourCommand, StoreBusinessHourDto?>
{ {
private readonly IStoreRepository _storeRepository = storeRepository; private readonly IStoreRepository _storeRepository = storeRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ILogger<UpdateStoreBusinessHourCommandHandler> _logger = logger; private readonly ILogger<UpdateStoreBusinessHourCommandHandler> _logger = logger;
/// <inheritdoc /> /// <inheritdoc />
public async Task<StoreBusinessHourDto?> Handle(UpdateStoreBusinessHourCommand request, CancellationToken cancellationToken) public async Task<StoreBusinessHourDto?> Handle(UpdateStoreBusinessHourCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取时段 // 1. 读取门店并解析租户
var tenantId = _tenantProvider.GetCurrentTenantId(); var store = await _storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return null;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取时段
var existing = await _storeRepository.FindBusinessHourByIdAsync(request.BusinessHourId, tenantId, cancellationToken); var existing = await _storeRepository.FindBusinessHourByIdAsync(request.BusinessHourId, tenantId, cancellationToken);
if (existing is null) if (existing is null)
{ {
return null; return null;
} }
// 2. 校验门店归属 // 3. (空行后) 校验门店归属
if (existing.StoreId != request.StoreId) if (existing.StoreId != request.StoreId)
{ {
throw new BusinessException(ErrorCodes.ValidationFailed, "营业时段不属于该门店"); throw new BusinessException(ErrorCodes.ValidationFailed, "营业时段不属于该门店");
} }
// 3. 更新字段 // 4. (空行后) 更新字段
existing.DayOfWeek = request.DayOfWeek; existing.DayOfWeek = request.DayOfWeek;
existing.HourType = request.HourType; existing.HourType = request.HourType;
existing.StartTime = request.StartTime; existing.StartTime = request.StartTime;
@@ -48,12 +52,12 @@ public sealed class UpdateStoreBusinessHourCommandHandler(
existing.CapacityLimit = request.CapacityLimit; existing.CapacityLimit = request.CapacityLimit;
existing.Notes = request.Notes?.Trim(); existing.Notes = request.Notes?.Trim();
// 4. 持久化 // 5. (空行后) 持久化
await _storeRepository.UpdateBusinessHourAsync(existing, cancellationToken); await _storeRepository.UpdateBusinessHourAsync(existing, cancellationToken);
await _storeRepository.SaveChangesAsync(cancellationToken); await _storeRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("更新营业时段 {BusinessHourId} 对应门店 {StoreId}", existing.Id, existing.StoreId); _logger.LogInformation("更新营业时段 {BusinessHourId} 对应门店 {StoreId}", existing.Id, existing.StoreId);
// 5. 返回 DTO // 6. (空行后) 返回 DTO
return StoreMapping.ToDto(existing); return StoreMapping.ToDto(existing);
} }
} }

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -16,35 +15,41 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
public sealed class UpdateStoreEmployeeShiftCommandHandler( public sealed class UpdateStoreEmployeeShiftCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
IMerchantRepository merchantRepository, IMerchantRepository merchantRepository,
ITenantProvider tenantProvider,
ILogger<UpdateStoreEmployeeShiftCommandHandler> logger) ILogger<UpdateStoreEmployeeShiftCommandHandler> logger)
: IRequestHandler<UpdateStoreEmployeeShiftCommand, StoreEmployeeShiftDto?> : IRequestHandler<UpdateStoreEmployeeShiftCommand, StoreEmployeeShiftDto?>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<StoreEmployeeShiftDto?> Handle(UpdateStoreEmployeeShiftCommand request, CancellationToken cancellationToken) public async Task<StoreEmployeeShiftDto?> Handle(UpdateStoreEmployeeShiftCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取排班 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return null;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取排班
var shift = await storeRepository.FindShiftByIdAsync(request.ShiftId, tenantId, cancellationToken); var shift = await storeRepository.FindShiftByIdAsync(request.ShiftId, tenantId, cancellationToken);
if (shift is null) if (shift is null)
{ {
return null; return null;
} }
// 2. 校验门店归属 // 3. (空行后) 校验门店归属
if (shift.StoreId != request.StoreId) if (shift.StoreId != request.StoreId)
{ {
throw new BusinessException(ErrorCodes.ValidationFailed, "排班不属于该门店"); throw new BusinessException(ErrorCodes.ValidationFailed, "排班不属于该门店");
} }
// 3. 校验员工归属 // 4. (空行后) 校验员工归属
var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken); var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken);
if (staff is null || (staff.StoreId.HasValue && staff.StoreId != request.StoreId)) if (staff is null || (staff.StoreId.HasValue && staff.StoreId != request.StoreId))
{ {
throw new BusinessException(ErrorCodes.ValidationFailed, "员工不存在或不属于该门店"); throw new BusinessException(ErrorCodes.ValidationFailed, "员工不存在或不属于该门店");
} }
// 4. 冲突校验 // 5. (空行后) 冲突校验
var shifts = await storeRepository.GetShiftsAsync(request.StoreId, tenantId, request.ShiftDate.Date, request.ShiftDate.Date, cancellationToken); var shifts = await storeRepository.GetShiftsAsync(request.StoreId, tenantId, request.ShiftDate.Date, request.ShiftDate.Date, cancellationToken);
var hasConflict = shifts.Any(x => x.Id != request.ShiftId && x.StaffId == request.StaffId && x.ShiftDate == request.ShiftDate); var hasConflict = shifts.Any(x => x.Id != request.ShiftId && x.StaffId == request.StaffId && x.ShiftDate == request.ShiftDate);
if (hasConflict) if (hasConflict)
@@ -52,7 +57,7 @@ public sealed class UpdateStoreEmployeeShiftCommandHandler(
throw new BusinessException(ErrorCodes.Conflict, "该员工当日已存在排班"); throw new BusinessException(ErrorCodes.Conflict, "该员工当日已存在排班");
} }
// 5. 更新字段 // 6. (空行后) 更新字段
shift.StaffId = request.StaffId; shift.StaffId = request.StaffId;
shift.ShiftDate = request.ShiftDate.Date; shift.ShiftDate = request.ShiftDate.Date;
shift.StartTime = request.StartTime; shift.StartTime = request.StartTime;
@@ -60,12 +65,12 @@ public sealed class UpdateStoreEmployeeShiftCommandHandler(
shift.RoleType = request.RoleType; shift.RoleType = request.RoleType;
shift.Notes = request.Notes?.Trim(); shift.Notes = request.Notes?.Trim();
// 6. 持久化 // 7. (空行后) 持久化
await storeRepository.UpdateShiftAsync(shift, cancellationToken); await storeRepository.UpdateShiftAsync(shift, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("更新排班 {ShiftId} 员工 {StaffId} 门店 {StoreId}", shift.Id, shift.StaffId, shift.StoreId); logger.LogInformation("更新排班 {ShiftId} 员工 {StaffId} 门店 {StoreId}", shift.Id, shift.StaffId, shift.StoreId);
// 7. 返回 DTO // 8. (空行后) 返回 DTO
return StoreMapping.ToDto(shift); return StoreMapping.ToDto(shift);
} }
} }

View File

@@ -5,7 +5,6 @@ using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -14,22 +13,28 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class UpdateStorePickupSlotCommandHandler( public sealed class UpdateStorePickupSlotCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<UpdateStorePickupSlotCommandHandler> logger) ILogger<UpdateStorePickupSlotCommandHandler> logger)
: IRequestHandler<UpdateStorePickupSlotCommand, StorePickupSlotDto?> : IRequestHandler<UpdateStorePickupSlotCommand, StorePickupSlotDto?>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<StorePickupSlotDto?> Handle(UpdateStorePickupSlotCommand request, CancellationToken cancellationToken) public async Task<StorePickupSlotDto?> Handle(UpdateStorePickupSlotCommand request, CancellationToken cancellationToken)
{ {
// 1. 查询档期 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return null;
}
var tenantId = store.TenantId;
// 2. (空行后) 查询档期
var slot = await storeRepository.FindPickupSlotByIdAsync(request.SlotId, tenantId, cancellationToken); var slot = await storeRepository.FindPickupSlotByIdAsync(request.SlotId, tenantId, cancellationToken);
if (slot is null || slot.StoreId != request.StoreId) if (slot is null || slot.StoreId != request.StoreId)
{ {
return null; return null;
} }
// 2. 更新字段 // 3. (空行后) 更新字段
slot.Name = request.Name.Trim(); slot.Name = request.Name.Trim();
slot.StartTime = request.StartTime; slot.StartTime = request.StartTime;
slot.EndTime = request.EndTime; slot.EndTime = request.EndTime;

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,7 +14,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class UpdateStoreQualificationCommandHandler( public sealed class UpdateStoreQualificationCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<UpdateStoreQualificationCommandHandler> logger) ILogger<UpdateStoreQualificationCommandHandler> logger)
: IRequestHandler<UpdateStoreQualificationCommand, StoreQualificationDto?> : IRequestHandler<UpdateStoreQualificationCommand, StoreQualificationDto?>
{ {
@@ -23,12 +21,12 @@ public sealed class UpdateStoreQualificationCommandHandler(
public async Task<StoreQualificationDto?> Handle(UpdateStoreQualificationCommand request, CancellationToken cancellationToken) public async Task<StoreQualificationDto?> Handle(UpdateStoreQualificationCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. (空行后) 审核中门店禁止修改资质 // 2. (空行后) 审核中门店禁止修改资质
if (store.AuditStatus == StoreAuditStatus.Pending) if (store.AuditStatus == StoreAuditStatus.Pending)

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -16,7 +15,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
public sealed class UpdateStoreStaffCommandHandler( public sealed class UpdateStoreStaffCommandHandler(
IMerchantRepository merchantRepository, IMerchantRepository merchantRepository,
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<UpdateStoreStaffCommandHandler> logger) ILogger<UpdateStoreStaffCommandHandler> logger)
: IRequestHandler<UpdateStoreStaffCommand, StoreStaffDto?> : IRequestHandler<UpdateStoreStaffCommand, StoreStaffDto?>
{ {
@@ -24,32 +22,32 @@ public sealed class UpdateStoreStaffCommandHandler(
public async Task<StoreStaffDto?> Handle(UpdateStoreStaffCommand request, CancellationToken cancellationToken) public async Task<StoreStaffDto?> Handle(UpdateStoreStaffCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店 // 1. 校验门店
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
return null; return null;
} }
var tenantId = store.TenantId;
// 2. 读取员工 // 2. (空行后) 读取员工
var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken); var staff = await merchantRepository.FindStaffByIdAsync(request.StaffId, tenantId, cancellationToken);
if (staff is null || staff.StoreId != request.StoreId) if (staff is null || staff.StoreId != request.StoreId)
{ {
return null; return null;
} }
// 3. 更新字段 // 3. (空行后) 更新字段
staff.Name = request.Name.Trim(); staff.Name = request.Name.Trim();
staff.Phone = request.Phone.Trim(); staff.Phone = request.Phone.Trim();
staff.Email = request.Email?.Trim(); staff.Email = request.Email?.Trim();
staff.RoleType = request.RoleType; staff.RoleType = request.RoleType;
staff.Status = request.Status; staff.Status = request.Status;
// 4. 持久化 // 4. (空行后) 持久化
await merchantRepository.SaveChangesAsync(cancellationToken); await merchantRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("更新门店员工 {StaffId} 门店 {StoreId}", staff.Id, staff.StoreId); logger.LogInformation("更新门店员工 {StaffId} 门店 {StoreId}", staff.Id, staff.StoreId);
// 5. 返回 DTO // 5. (空行后) 返回 DTO
return StoreMapping.ToDto(staff); return StoreMapping.ToDto(staff);
} }
} }

View File

@@ -5,7 +5,6 @@ using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -14,28 +13,34 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class UpdateStoreTableAreaCommandHandler( public sealed class UpdateStoreTableAreaCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<UpdateStoreTableAreaCommandHandler> logger) ILogger<UpdateStoreTableAreaCommandHandler> logger)
: IRequestHandler<UpdateStoreTableAreaCommand, StoreTableAreaDto?> : IRequestHandler<UpdateStoreTableAreaCommand, StoreTableAreaDto?>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<StoreTableAreaDto?> Handle(UpdateStoreTableAreaCommand request, CancellationToken cancellationToken) public async Task<StoreTableAreaDto?> Handle(UpdateStoreTableAreaCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取区域 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return null;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取区域
var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId, tenantId, cancellationToken); var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId, tenantId, cancellationToken);
if (area is null) if (area is null)
{ {
return null; return null;
} }
// 2. 校验门店归属 // 3. (空行后) 校验门店归属
if (area.StoreId != request.StoreId) if (area.StoreId != request.StoreId)
{ {
throw new BusinessException(ErrorCodes.ValidationFailed, "区域不属于该门店"); throw new BusinessException(ErrorCodes.ValidationFailed, "区域不属于该门店");
} }
// 3. 名称唯一校验 // 4. (空行后) 名称唯一校验
var areas = await storeRepository.GetTableAreasAsync(request.StoreId, tenantId, cancellationToken); var areas = await storeRepository.GetTableAreasAsync(request.StoreId, tenantId, cancellationToken);
var hasDuplicate = areas.Any(x => x.Id != request.AreaId && x.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase)); var hasDuplicate = areas.Any(x => x.Id != request.AreaId && x.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
if (hasDuplicate) if (hasDuplicate)
@@ -43,17 +48,17 @@ public sealed class UpdateStoreTableAreaCommandHandler(
throw new BusinessException(ErrorCodes.Conflict, "区域名称已存在"); throw new BusinessException(ErrorCodes.Conflict, "区域名称已存在");
} }
// 4. 更新字段 // 5. (空行后) 更新字段
area.Name = request.Name.Trim(); area.Name = request.Name.Trim();
area.Description = request.Description?.Trim(); area.Description = request.Description?.Trim();
area.SortOrder = request.SortOrder; area.SortOrder = request.SortOrder;
// 5. 持久化 // 6. (空行后) 持久化
await storeRepository.UpdateTableAreaAsync(area, cancellationToken); await storeRepository.UpdateTableAreaAsync(area, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("更新桌台区域 {AreaId} 对应门店 {StoreId}", area.Id, area.StoreId); logger.LogInformation("更新桌台区域 {AreaId} 对应门店 {StoreId}", area.Id, area.StoreId);
// 6. 返回 DTO // 7. (空行后) 返回 DTO
return StoreMapping.ToDto(area); return StoreMapping.ToDto(area);
} }
} }

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,28 +14,34 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class UpdateStoreTableCommandHandler( public sealed class UpdateStoreTableCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<UpdateStoreTableCommandHandler> logger) ILogger<UpdateStoreTableCommandHandler> logger)
: IRequestHandler<UpdateStoreTableCommand, StoreTableDto?> : IRequestHandler<UpdateStoreTableCommand, StoreTableDto?>
{ {
/// <inheritdoc /> /// <inheritdoc />
public async Task<StoreTableDto?> Handle(UpdateStoreTableCommand request, CancellationToken cancellationToken) public async Task<StoreTableDto?> Handle(UpdateStoreTableCommand request, CancellationToken cancellationToken)
{ {
// 1. 读取桌码 // 1. 读取门店并解析租户
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
if (store is null)
{
return null;
}
var tenantId = store.TenantId;
// 2. (空行后) 读取桌码
var table = await storeRepository.FindTableByIdAsync(request.TableId, tenantId, cancellationToken); var table = await storeRepository.FindTableByIdAsync(request.TableId, tenantId, cancellationToken);
if (table is null) if (table is null)
{ {
return null; return null;
} }
// 2. 校验门店归属 // 3. (空行后) 校验门店归属
if (table.StoreId != request.StoreId) if (table.StoreId != request.StoreId)
{ {
throw new BusinessException(ErrorCodes.ValidationFailed, "桌码不属于该门店"); throw new BusinessException(ErrorCodes.ValidationFailed, "桌码不属于该门店");
} }
// 3. 校验区域归属 // 4. (空行后) 校验区域归属
if (request.AreaId.HasValue) if (request.AreaId.HasValue)
{ {
var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId.Value, tenantId, cancellationToken); var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId.Value, tenantId, cancellationToken);
@@ -46,7 +51,7 @@ public sealed class UpdateStoreTableCommandHandler(
} }
} }
// 4. 校验桌码唯一 // 5. (空行后) 校验桌码唯一
var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken); var tables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken);
var exists = tables.Any(x => x.Id != request.TableId && x.TableCode.Equals(request.TableCode, StringComparison.OrdinalIgnoreCase)); var exists = tables.Any(x => x.Id != request.TableId && x.TableCode.Equals(request.TableCode, StringComparison.OrdinalIgnoreCase));
if (exists) if (exists)
@@ -54,19 +59,19 @@ public sealed class UpdateStoreTableCommandHandler(
throw new BusinessException(ErrorCodes.Conflict, "桌码已存在"); throw new BusinessException(ErrorCodes.Conflict, "桌码已存在");
} }
// 5. 更新字段 // 6. (空行后) 更新字段
table.AreaId = request.AreaId; table.AreaId = request.AreaId;
table.TableCode = request.TableCode.Trim(); table.TableCode = request.TableCode.Trim();
table.Capacity = request.Capacity; table.Capacity = request.Capacity;
table.Tags = request.Tags?.Trim(); table.Tags = request.Tags?.Trim();
table.Status = request.Status; table.Status = request.Status;
// 6. 持久化 // 7. (空行后) 持久化
await storeRepository.UpdateTableAsync(table, cancellationToken); await storeRepository.UpdateTableAsync(table, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken); await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("更新桌码 {TableId} 对应门店 {StoreId}", table.Id, table.StoreId); logger.LogInformation("更新桌码 {TableId} 对应门店 {StoreId}", table.Id, table.StoreId);
// 7. 返回 DTO // 8. (空行后) 返回 DTO
return StoreMapping.ToDto(table); return StoreMapping.ToDto(table);
} }
} }

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers; namespace TakeoutSaaS.Application.App.Stores.Handlers;
@@ -15,7 +14,6 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// </summary> /// </summary>
public sealed class UpsertStorePickupSettingCommandHandler( public sealed class UpsertStorePickupSettingCommandHandler(
IStoreRepository storeRepository, IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<UpsertStorePickupSettingCommandHandler> logger) ILogger<UpsertStorePickupSettingCommandHandler> logger)
: IRequestHandler<UpsertStorePickupSettingCommand, StorePickupSettingDto> : IRequestHandler<UpsertStorePickupSettingCommand, StorePickupSettingDto>
{ {
@@ -23,14 +21,14 @@ public sealed class UpsertStorePickupSettingCommandHandler(
public async Task<StorePickupSettingDto> Handle(UpsertStorePickupSettingCommand request, CancellationToken cancellationToken) public async Task<StorePickupSettingDto> Handle(UpsertStorePickupSettingCommand request, CancellationToken cancellationToken)
{ {
// 1. 校验门店存在 // 1. 校验门店存在
var tenantId = tenantProvider.GetCurrentTenantId(); var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
if (store is null) if (store is null)
{ {
throw new BusinessException(ErrorCodes.NotFound, "门店不存在"); throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
} }
var tenantId = store.TenantId;
// 2. 读取或创建配置 // 2. (空行后) 读取或创建配置
var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken); var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken);
if (setting is null) if (setting is null)
{ {
@@ -42,7 +40,7 @@ public sealed class UpsertStorePickupSettingCommandHandler(
await storeRepository.AddPickupSettingAsync(setting, cancellationToken); await storeRepository.AddPickupSettingAsync(setting, cancellationToken);
} }
// 3. 更新字段 // 3. (空行后) 更新字段
setting.AllowToday = request.AllowToday; setting.AllowToday = request.AllowToday;
setting.AllowDaysAhead = request.AllowDaysAhead; setting.AllowDaysAhead = request.AllowDaysAhead;
setting.DefaultCutoffMinutes = request.DefaultCutoffMinutes; setting.DefaultCutoffMinutes = request.DefaultCutoffMinutes;

View File

@@ -8,6 +8,11 @@ namespace TakeoutSaaS.Application.App.Stores.Queries;
/// </summary> /// </summary>
public sealed record GetStoreTableContextQuery : IRequest<StoreTableContextDto?> public sealed record GetStoreTableContextQuery : IRequest<StoreTableContextDto?>
{ {
/// <summary>
/// 租户 ID。
/// </summary>
public long TenantId { get; init; }
/// <summary> /// <summary>
/// 桌码。 /// 桌码。
/// </summary> /// </summary>

View File

@@ -13,6 +13,7 @@ public sealed class GetStoreTableContextQueryValidator : AbstractValidator<GetSt
/// </summary> /// </summary>
public GetStoreTableContextQueryValidator() public GetStoreTableContextQueryValidator()
{ {
RuleFor(x => x.TenantId).GreaterThan(0);
RuleFor(x => x.TableCode).NotEmpty().MaximumLength(32); RuleFor(x => x.TableCode).NotEmpty().MaximumLength(32);
} }
} }