完成门店管理后端接口与任务

This commit is contained in:
2026-01-01 07:26:14 +08:00
parent dc9f6136d6
commit fc55003d3d
131 changed files with 15333 additions and 201 deletions

View File

@@ -1,25 +1,54 @@
using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores;
using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Stores.Handlers;
/// <summary>
/// 创建门店命令处理器。
/// </summary>
public sealed class CreateStoreCommandHandler(IStoreRepository storeRepository, ILogger<CreateStoreCommandHandler> logger)
public sealed class CreateStoreCommandHandler(
IStoreRepository storeRepository,
ITenantProvider tenantProvider,
ILogger<CreateStoreCommandHandler> logger)
: IRequestHandler<CreateStoreCommand, StoreDto>
{
private readonly IStoreRepository _storeRepository = storeRepository;
private readonly ILogger<CreateStoreCommandHandler> _logger = logger;
/// <inheritdoc />
public async Task<StoreDto> Handle(CreateStoreCommand request, CancellationToken cancellationToken)
{
// 1. 构建实体
// 1. 校验门店坐标唯一性100 米内禁止重复)
if (request.Longitude.HasValue && request.Latitude.HasValue)
{
var tenantId = tenantProvider.GetCurrentTenantId();
var isDuplicate = await storeRepository.ExistsStoreWithinDistanceAsync(
request.MerchantId,
tenantId,
request.Longitude.Value,
request.Latitude.Value,
100,
cancellationToken);
if (isDuplicate)
{
throw new BusinessException(ErrorCodes.Conflict, "该位置已存在门店");
}
}
// 2. (空行后) 计算审核与经营状态
var now = DateTime.UtcNow;
var isSameEntity = request.OwnershipType == StoreOwnershipType.SameEntity;
var auditStatus = isSameEntity ? StoreAuditStatus.Activated : StoreAuditStatus.Draft;
var businessStatus = StoreBusinessStatus.Resting;
DateTime? activatedAt = isSameEntity ? now : null;
// 3. (空行后) 构建实体
var store = new Store
{
MerchantId = request.MerchantId,
@@ -28,6 +57,12 @@ public sealed class CreateStoreCommandHandler(IStoreRepository storeRepository,
Phone = request.Phone?.Trim(),
ManagerName = request.ManagerName?.Trim(),
Status = request.Status,
SignboardImageUrl = request.SignboardImageUrl?.Trim(),
OwnershipType = request.OwnershipType,
AuditStatus = auditStatus,
BusinessStatus = businessStatus,
CategoryId = request.CategoryId,
ActivatedAt = activatedAt,
Province = request.Province?.Trim(),
City = request.City?.Trim(),
District = request.District?.Trim(),
@@ -44,39 +79,20 @@ public sealed class CreateStoreCommandHandler(IStoreRepository storeRepository,
SupportsQueueing = request.SupportsQueueing
};
// 2. 持久化
await _storeRepository.AddStoreAsync(store, cancellationToken);
await _storeRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("创建门店 {StoreId} - {StoreName}", store.Id, store.Name);
// 4. (空行后) 持久化并初始化费用配置
await storeRepository.AddStoreAsync(store, cancellationToken);
await storeRepository.AddStoreFeeAsync(new StoreFee
{
StoreId = store.Id,
MinimumOrderAmount = 0m,
BaseDeliveryFee = 0m,
PackagingFeeMode = PackagingFeeMode.Fixed,
FixedPackagingFee = 0m
}, cancellationToken);
await storeRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("创建门店 {StoreId} - {StoreName}", store.Id, store.Name);
// 3. 返回 DTO
return MapToDto(store);
// 5. (空行后) 返回 DTO
return StoreMapping.ToDto(store);
}
private static StoreDto MapToDto(Store store) => new()
{
Id = store.Id,
TenantId = store.TenantId,
MerchantId = store.MerchantId,
Code = store.Code,
Name = store.Name,
Phone = store.Phone,
ManagerName = store.ManagerName,
Status = store.Status,
Province = store.Province,
City = store.City,
District = store.District,
Address = store.Address,
Longitude = store.Longitude,
Latitude = store.Latitude,
Announcement = store.Announcement,
Tags = store.Tags,
DeliveryRadiusKm = store.DeliveryRadiusKm,
SupportsDineIn = store.SupportsDineIn,
SupportsPickup = store.SupportsPickup,
SupportsDelivery = store.SupportsDelivery,
SupportsReservation = store.SupportsReservation,
SupportsQueueing = store.SupportsQueueing,
CreatedAt = store.CreatedAt
};
}