chore: add documentation comments and stylecop rules

This commit is contained in:
2025-12-04 11:25:01 +08:00
parent 17d143a351
commit 8e4c2b0e45
142 changed files with 1309 additions and 439 deletions

View File

@@ -22,20 +22,17 @@ public sealed class AddMerchantDocumentCommandHandler(
ICurrentUserAccessor currentUserAccessor)
: IRequestHandler<AddMerchantDocumentCommand, MerchantDocumentDto>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly IIdGenerator _idGenerator = idGenerator;
private readonly ICurrentUserAccessor _currentUserAccessor = currentUserAccessor;
public async Task<MerchantDocumentDto> Handle(AddMerchantDocumentCommand request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var merchant = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
// 1. 获取租户并查询商户
var tenantId = tenantProvider.GetCurrentTenantId();
var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
// 2. 构建证照记录
var document = new MerchantDocument
{
Id = _idGenerator.NextId(),
Id = idGenerator.NextId(),
MerchantId = merchant.Id,
DocumentType = request.DocumentType,
Status = MerchantDocumentStatus.Pending,
@@ -45,8 +42,9 @@ public sealed class AddMerchantDocumentCommandHandler(
ExpiresAt = request.ExpiresAt
};
await _merchantRepository.AddDocumentAsync(document, cancellationToken);
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
// 3. 持久化与审计
await merchantRepository.AddDocumentAsync(document, cancellationToken);
await merchantRepository.AddAuditLogAsync(new MerchantAuditLog
{
TenantId = tenantId,
MerchantId = merchant.Id,
@@ -57,20 +55,21 @@ public sealed class AddMerchantDocumentCommandHandler(
OperatorName = ResolveOperatorName()
}, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
// 4. 返回 DTO
return MerchantMapping.ToDto(document);
}
private long? ResolveOperatorId()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? null : id;
}
private string ResolveOperatorName()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? "system" : $"user:{id}";
}
}

View File

@@ -18,22 +18,23 @@ public sealed class CreateMerchantCategoryCommandHandler(
ITenantProvider tenantProvider)
: IRequestHandler<CreateMerchantCategoryCommand, MerchantCategoryDto>
{
private readonly IMerchantCategoryRepository _categoryRepository = categoryRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<MerchantCategoryDto> Handle(CreateMerchantCategoryCommand request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
var normalizedName = request.Name.Trim();
if (await _categoryRepository.ExistsAsync(normalizedName, tenantId, cancellationToken))
// 2. 检查重名
if (await categoryRepository.ExistsAsync(normalizedName, tenantId, cancellationToken))
{
throw new BusinessException(ErrorCodes.Conflict, $"类目“{normalizedName}”已存在");
}
var categories = await _categoryRepository.ListAsync(tenantId, cancellationToken);
// 3. 计算排序
var categories = await categoryRepository.ListAsync(tenantId, cancellationToken);
var targetOrder = request.DisplayOrder ?? (categories.Count == 0 ? 1 : categories.Max(x => x.DisplayOrder) + 1);
// 4. 构建实体
var entity = new MerchantCategory
{
Name = normalizedName,
@@ -41,8 +42,9 @@ public sealed class CreateMerchantCategoryCommandHandler(
IsActive = request.IsActive
};
await _categoryRepository.AddAsync(entity, cancellationToken);
await _categoryRepository.SaveChangesAsync(cancellationToken);
// 5. 持久化并返回
await categoryRepository.AddAsync(entity, cancellationToken);
await categoryRepository.SaveChangesAsync(cancellationToken);
return MerchantMapping.ToDto(entity);
}

View File

@@ -13,12 +13,10 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers;
public sealed class CreateMerchantCommandHandler(IMerchantRepository merchantRepository, ILogger<CreateMerchantCommandHandler> logger)
: IRequestHandler<CreateMerchantCommand, MerchantDto>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ILogger<CreateMerchantCommandHandler> _logger = logger;
/// <inheritdoc />
public async Task<MerchantDto> Handle(CreateMerchantCommand request, CancellationToken cancellationToken)
{
// 1. 构建商户实体
var merchant = new Merchant
{
BrandName = request.BrandName.Trim(),
@@ -31,10 +29,12 @@ public sealed class CreateMerchantCommandHandler(IMerchantRepository merchantRep
JoinedAt = DateTime.UtcNow
};
await _merchantRepository.AddMerchantAsync(merchant, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
// 2. 持久化
await merchantRepository.AddMerchantAsync(merchant, cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("创建商户 {MerchantId} - {BrandName}", merchant.Id, merchant.BrandName);
// 3. 记录日志
logger.LogInformation("创建商户 {MerchantId} - {BrandName}", merchant.Id, merchant.BrandName);
return MapToDto(merchant);
}

View File

@@ -22,25 +22,23 @@ public sealed class CreateMerchantContractCommandHandler(
ICurrentUserAccessor currentUserAccessor)
: IRequestHandler<CreateMerchantContractCommand, MerchantContractDto>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly IIdGenerator _idGenerator = idGenerator;
private readonly ICurrentUserAccessor _currentUserAccessor = currentUserAccessor;
public async Task<MerchantContractDto> Handle(CreateMerchantContractCommand request, CancellationToken cancellationToken)
{
// 1. 校验时间
if (request.EndDate <= request.StartDate)
{
throw new BusinessException(ErrorCodes.BadRequest, "合同结束时间必须晚于开始时间");
}
var tenantId = _tenantProvider.GetCurrentTenantId();
var merchant = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
// 2. 查询商户
var tenantId = tenantProvider.GetCurrentTenantId();
var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
// 3. 构建合同
var contract = new MerchantContract
{
Id = _idGenerator.NextId(),
Id = idGenerator.NextId(),
MerchantId = merchant.Id,
ContractNumber = request.ContractNumber.Trim(),
StartDate = request.StartDate,
@@ -48,8 +46,9 @@ public sealed class CreateMerchantContractCommandHandler(
FileUrl = request.FileUrl.Trim()
};
await _merchantRepository.AddContractAsync(contract, cancellationToken);
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
// 4. 持久化与审计
await merchantRepository.AddContractAsync(contract, cancellationToken);
await merchantRepository.AddAuditLogAsync(new MerchantAuditLog
{
TenantId = tenantId,
MerchantId = merchant.Id,
@@ -60,19 +59,21 @@ public sealed class CreateMerchantContractCommandHandler(
OperatorName = ResolveOperatorName()
}, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
// 5. 返回 DTO
return MerchantMapping.ToDto(contract);
}
private long? ResolveOperatorId()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? null : id;
}
private string ResolveOperatorName()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? "system" : $"user:{id}";
}
}

View File

@@ -13,21 +13,20 @@ public sealed class DeleteMerchantCategoryCommandHandler(
ITenantProvider tenantProvider)
: IRequestHandler<DeleteMerchantCategoryCommand, bool>
{
private readonly IMerchantCategoryRepository _categoryRepository = categoryRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<bool> Handle(DeleteMerchantCategoryCommand request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var existing = await _categoryRepository.FindByIdAsync(request.CategoryId, tenantId, cancellationToken);
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
var existing = await categoryRepository.FindByIdAsync(request.CategoryId, tenantId, cancellationToken);
if (existing == null)
{
return false;
}
await _categoryRepository.RemoveAsync(existing, cancellationToken);
await _categoryRepository.SaveChangesAsync(cancellationToken);
// 2. 删除并保存
await categoryRepository.RemoveAsync(existing, cancellationToken);
await categoryRepository.SaveChangesAsync(cancellationToken);
return true;
}
}

View File

@@ -15,25 +15,21 @@ public sealed class DeleteMerchantCommandHandler(
ILogger<DeleteMerchantCommandHandler> logger)
: IRequestHandler<DeleteMerchantCommand, bool>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ILogger<DeleteMerchantCommandHandler> _logger = logger;
/// <inheritdoc />
public async Task<bool> Handle(DeleteMerchantCommand request, CancellationToken cancellationToken)
{
// 1. 校验存在性
var tenantId = _tenantProvider.GetCurrentTenantId();
var existing = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken);
var tenantId = tenantProvider.GetCurrentTenantId();
var existing = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken);
if (existing == null)
{
return false;
}
// 2. 删除
await _merchantRepository.DeleteMerchantAsync(request.MerchantId, tenantId, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("删除商户 {MerchantId}", request.MerchantId);
await merchantRepository.DeleteMerchantAsync(request.MerchantId, tenantId, cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("删除商户 {MerchantId}", request.MerchantId);
return true;
}

View File

@@ -16,20 +16,21 @@ public sealed class GetMerchantAuditLogsQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<GetMerchantAuditLogsQuery, PagedResult<MerchantAuditLogDto>>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<PagedResult<MerchantAuditLogDto>> Handle(GetMerchantAuditLogsQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var logs = await _merchantRepository.GetAuditLogsAsync(request.MerchantId, tenantId, cancellationToken);
// 1. 获取租户上下文并查询日志
var tenantId = tenantProvider.GetCurrentTenantId();
var logs = await merchantRepository.GetAuditLogsAsync(request.MerchantId, tenantId, cancellationToken);
var total = logs.Count;
// 2. 分页映射
var paged = logs
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.Select(MerchantMapping.ToDto)
.ToList();
// 3. 返回结果
return new PagedResult<MerchantAuditLogDto>(paged, request.Page, request.PageSize, total);
}
}

View File

@@ -12,19 +12,18 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers;
public sealed class GetMerchantByIdQueryHandler(IMerchantRepository merchantRepository, ITenantProvider tenantProvider)
: IRequestHandler<GetMerchantByIdQuery, MerchantDto?>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
/// <inheritdoc />
public async Task<MerchantDto?> Handle(GetMerchantByIdQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var merchant = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken);
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken);
if (merchant == null)
{
return null;
}
// 2. 返回 DTO
return new MerchantDto
{
Id = merchant.Id,

View File

@@ -15,14 +15,13 @@ public sealed class GetMerchantCategoriesQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<GetMerchantCategoriesQuery, IReadOnlyList<string>>
{
private readonly IMerchantCategoryRepository _categoryRepository = categoryRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<IReadOnlyList<string>> Handle(GetMerchantCategoriesQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var categories = await _categoryRepository.ListAsync(tenantId, cancellationToken);
// 1. 获取租户上下文并读取类目
var tenantId = tenantProvider.GetCurrentTenantId();
var categories = await categoryRepository.ListAsync(tenantId, cancellationToken);
// 2. 过滤启用类目并去重
return categories
.Where(x => x.IsActive)
.Select(x => x.Name.Trim())

View File

@@ -17,16 +17,15 @@ public sealed class GetMerchantContractsQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<GetMerchantContractsQuery, IReadOnlyList<MerchantContractDto>>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<IReadOnlyList<MerchantContractDto>> Handle(GetMerchantContractsQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
_ = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
// 1. 获取租户上下文并校验商户存在
var tenantId = tenantProvider.GetCurrentTenantId();
_ = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
var contracts = await _merchantRepository.GetContractsAsync(request.MerchantId, tenantId, cancellationToken);
// 2. 查询合同列表
var contracts = await merchantRepository.GetContractsAsync(request.MerchantId, tenantId, cancellationToken);
return MerchantMapping.ToContractDtos(contracts);
}
}

View File

@@ -16,18 +16,18 @@ public sealed class GetMerchantDetailQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<GetMerchantDetailQuery, MerchantDetailDto>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<MerchantDetailDto> Handle(GetMerchantDetailQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var merchant = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
// 1. 获取租户上下文并查询商户
var tenantId = tenantProvider.GetCurrentTenantId();
var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
var documents = await _merchantRepository.GetDocumentsAsync(request.MerchantId, tenantId, cancellationToken);
var contracts = await _merchantRepository.GetContractsAsync(request.MerchantId, tenantId, cancellationToken);
// 2. 查询证照与合同
var documents = await merchantRepository.GetDocumentsAsync(request.MerchantId, tenantId, cancellationToken);
var contracts = await merchantRepository.GetContractsAsync(request.MerchantId, tenantId, cancellationToken);
// 3. 返回明细 DTO
return new MerchantDetailDto
{
Merchant = MerchantMapping.ToDto(merchant),

View File

@@ -17,16 +17,15 @@ public sealed class GetMerchantDocumentsQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<GetMerchantDocumentsQuery, IReadOnlyList<MerchantDocumentDto>>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<IReadOnlyList<MerchantDocumentDto>> Handle(GetMerchantDocumentsQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
_ = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
// 1. 获取租户上下文并校验商户存在
var tenantId = tenantProvider.GetCurrentTenantId();
_ = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
var documents = await _merchantRepository.GetDocumentsAsync(request.MerchantId, tenantId, cancellationToken);
// 2. 查询证照列表
var documents = await merchantRepository.GetDocumentsAsync(request.MerchantId, tenantId, cancellationToken);
return MerchantMapping.ToDocumentDtos(documents);
}
}

View File

@@ -15,13 +15,13 @@ public sealed class ListMerchantCategoriesQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<ListMerchantCategoriesQuery, IReadOnlyList<MerchantCategoryDto>>
{
private readonly IMerchantCategoryRepository _categoryRepository = categoryRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<IReadOnlyList<MerchantCategoryDto>> Handle(ListMerchantCategoriesQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var categories = await _categoryRepository.ListAsync(tenantId, cancellationToken);
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
var categories = await categoryRepository.ListAsync(tenantId, cancellationToken);
// 2. 映射 DTO
return MerchantMapping.ToCategoryDtos(categories);
}
}

View File

@@ -16,15 +16,14 @@ public sealed class ReorderMerchantCategoriesCommandHandler(
ITenantProvider tenantProvider)
: IRequestHandler<ReorderMerchantCategoriesCommand, bool>
{
private readonly IMerchantCategoryRepository _categoryRepository = categoryRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
public async Task<bool> Handle(ReorderMerchantCategoriesCommand request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var categories = await _categoryRepository.ListAsync(tenantId, cancellationToken);
// 1. 获取租户并查询类目
var tenantId = tenantProvider.GetCurrentTenantId();
var categories = await categoryRepository.ListAsync(tenantId, cancellationToken);
var map = categories.ToDictionary(x => x.Id);
// 2. 更新排序
foreach (var item in request.Items)
{
if (!map.TryGetValue(item.CategoryId, out var category))
@@ -35,8 +34,9 @@ public sealed class ReorderMerchantCategoriesCommandHandler(
category.DisplayOrder = item.DisplayOrder;
}
await _categoryRepository.UpdateRangeAsync(map.Values, cancellationToken);
await _categoryRepository.SaveChangesAsync(cancellationToken);
// 3. 持久化
await categoryRepository.UpdateRangeAsync(map.Values, cancellationToken);
await categoryRepository.SaveChangesAsync(cancellationToken);
return true;
}
}

View File

@@ -20,21 +20,20 @@ public sealed class ReviewMerchantCommandHandler(
ICurrentUserAccessor currentUserAccessor)
: IRequestHandler<ReviewMerchantCommand, MerchantDto>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ICurrentUserAccessor _currentUserAccessor = currentUserAccessor;
public async Task<MerchantDto> Handle(ReviewMerchantCommand request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var merchant = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
// 1. 读取商户
var tenantId = tenantProvider.GetCurrentTenantId();
var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
// 2. 已审核通过则直接返回
if (request.Approve && merchant.Status == MerchantStatus.Approved)
{
return MerchantMapping.ToDto(merchant);
}
// 3. 更新审核状态
var previousStatus = merchant.Status;
merchant.Status = request.Approve ? MerchantStatus.Approved : MerchantStatus.Rejected;
merchant.ReviewRemarks = request.Remarks;
@@ -44,8 +43,9 @@ public sealed class ReviewMerchantCommandHandler(
merchant.JoinedAt = DateTime.UtcNow;
}
await _merchantRepository.UpdateMerchantAsync(merchant, cancellationToken);
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
// 4. 持久化与审计
await merchantRepository.UpdateMerchantAsync(merchant, cancellationToken);
await merchantRepository.AddAuditLogAsync(new MerchantAuditLog
{
TenantId = tenantId,
MerchantId = merchant.Id,
@@ -55,20 +55,21 @@ public sealed class ReviewMerchantCommandHandler(
OperatorId = ResolveOperatorId(),
OperatorName = ResolveOperatorName()
}, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
// 5. 返回 DTO
return MerchantMapping.ToDto(merchant);
}
private long? ResolveOperatorId()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? null : id;
}
private string ResolveOperatorName()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? "system" : $"user:{id}";
}
}

View File

@@ -20,27 +20,27 @@ public sealed class ReviewMerchantDocumentCommandHandler(
ICurrentUserAccessor currentUserAccessor)
: IRequestHandler<ReviewMerchantDocumentCommand, MerchantDocumentDto>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ICurrentUserAccessor _currentUserAccessor = currentUserAccessor;
public async Task<MerchantDocumentDto> Handle(ReviewMerchantDocumentCommand request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var document = await _merchantRepository.FindDocumentByIdAsync(request.MerchantId, tenantId, request.DocumentId, cancellationToken)
// 1. 读取证照
var tenantId = tenantProvider.GetCurrentTenantId();
var document = await merchantRepository.FindDocumentByIdAsync(request.MerchantId, tenantId, request.DocumentId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "证照不存在");
// 2. 若状态无变化且备注相同,直接返回
var targetStatus = request.Approve ? MerchantDocumentStatus.Approved : MerchantDocumentStatus.Rejected;
if (document.Status == targetStatus && document.Remarks == request.Remarks)
{
return MerchantMapping.ToDto(document);
}
// 3. 更新状态
document.Status = targetStatus;
document.Remarks = request.Remarks;
await _merchantRepository.UpdateDocumentAsync(document, cancellationToken);
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
// 4. 持久化与审计
await merchantRepository.UpdateDocumentAsync(document, cancellationToken);
await merchantRepository.AddAuditLogAsync(new MerchantAuditLog
{
TenantId = tenantId,
MerchantId = document.MerchantId,
@@ -50,20 +50,21 @@ public sealed class ReviewMerchantDocumentCommandHandler(
OperatorId = ResolveOperatorId(),
OperatorName = ResolveOperatorName()
}, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
// 5. 返回 DTO
return MerchantMapping.ToDto(document);
}
private long? ResolveOperatorId()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? null : id;
}
private string ResolveOperatorName()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? "system" : $"user:{id}";
}
}

View File

@@ -15,21 +15,21 @@ public sealed class SearchMerchantsQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<SearchMerchantsQuery, PagedResult<MerchantDto>>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
/// <inheritdoc />
public async Task<PagedResult<MerchantDto>> Handle(SearchMerchantsQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var merchants = await _merchantRepository.SearchAsync(tenantId, request.Status, cancellationToken);
// 1. 获取租户并查询商户
var tenantId = tenantProvider.GetCurrentTenantId();
var merchants = await merchantRepository.SearchAsync(tenantId, request.Status, cancellationToken);
// 2. 排序与分页
var sorted = ApplySorting(merchants, request.SortBy, request.SortDescending);
var paged = sorted
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.ToList();
// 3. 映射 DTO
var items = paged.Select(merchant => new MerchantDto
{
Id = merchant.Id,
@@ -45,6 +45,7 @@ public sealed class SearchMerchantsQueryHandler(
CreatedAt = merchant.CreatedAt
}).ToList();
// 4. 返回分页结果
return new PagedResult<MerchantDto>(items, request.Page, request.PageSize, merchants.Count);
}

View File

@@ -16,16 +16,12 @@ public sealed class UpdateMerchantCommandHandler(
ILogger<UpdateMerchantCommandHandler> logger)
: IRequestHandler<UpdateMerchantCommand, MerchantDto?>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ILogger<UpdateMerchantCommandHandler> _logger = logger;
/// <inheritdoc />
public async Task<MerchantDto?> Handle(UpdateMerchantCommand request, CancellationToken cancellationToken)
{
// 1. 读取现有商户
var tenantId = _tenantProvider.GetCurrentTenantId();
var existing = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken);
var tenantId = tenantProvider.GetCurrentTenantId();
var existing = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken);
if (existing == null)
{
return null;
@@ -41,9 +37,9 @@ public sealed class UpdateMerchantCommandHandler(
existing.Status = request.Status;
// 3. 持久化
await _merchantRepository.UpdateMerchantAsync(existing, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("更新商户 {MerchantId} - {BrandName}", existing.Id, existing.BrandName);
await merchantRepository.UpdateMerchantAsync(existing, cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
logger.LogInformation("更新商户 {MerchantId} - {BrandName}", existing.Id, existing.BrandName);
// 4. 返回 DTO
return MapToDto(existing);

View File

@@ -20,16 +20,14 @@ public sealed class UpdateMerchantContractStatusCommandHandler(
ICurrentUserAccessor currentUserAccessor)
: IRequestHandler<UpdateMerchantContractStatusCommand, MerchantContractDto>
{
private readonly IMerchantRepository _merchantRepository = merchantRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ICurrentUserAccessor _currentUserAccessor = currentUserAccessor;
public async Task<MerchantContractDto> Handle(UpdateMerchantContractStatusCommand request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var contract = await _merchantRepository.FindContractByIdAsync(request.MerchantId, tenantId, request.ContractId, cancellationToken)
// 1. 查询合同
var tenantId = tenantProvider.GetCurrentTenantId();
var contract = await merchantRepository.FindContractByIdAsync(request.MerchantId, tenantId, request.ContractId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "合同不存在");
// 2. 更新状态
if (request.Status == ContractStatus.Active)
{
contract.Status = ContractStatus.Active;
@@ -46,8 +44,9 @@ public sealed class UpdateMerchantContractStatusCommandHandler(
contract.Status = request.Status;
}
await _merchantRepository.UpdateContractAsync(contract, cancellationToken);
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
// 3. 持久化与审计
await merchantRepository.UpdateContractAsync(contract, cancellationToken);
await merchantRepository.AddAuditLogAsync(new MerchantAuditLog
{
TenantId = tenantId,
MerchantId = contract.MerchantId,
@@ -58,19 +57,21 @@ public sealed class UpdateMerchantContractStatusCommandHandler(
OperatorName = ResolveOperatorName()
}, cancellationToken);
await _merchantRepository.SaveChangesAsync(cancellationToken);
await merchantRepository.SaveChangesAsync(cancellationToken);
// 4. 返回 DTO
return MerchantMapping.ToDto(contract);
}
private long? ResolveOperatorId()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? null : id;
}
private string ResolveOperatorName()
{
var id = _currentUserAccessor.UserId;
var id = currentUserAccessor.UserId;
return id == 0 ? "system" : $"user:{id}";
}
}