feat: 商户类目数据库化并增加权限种子
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 新增商户证照。
|
||||
/// </summary>
|
||||
public sealed record AddMerchantDocumentCommand(
|
||||
[property: Required] long MerchantId,
|
||||
[property: Required] MerchantDocumentType DocumentType,
|
||||
[property: Required, MaxLength(512)] string FileUrl,
|
||||
[property: MaxLength(64)] string? DocumentNumber,
|
||||
DateTime? IssuedAt,
|
||||
DateTime? ExpiresAt) : IRequest<MerchantDocumentDto>;
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 新增商户类目。
|
||||
/// </summary>
|
||||
public sealed record CreateMerchantCategoryCommand(
|
||||
[property: Required, MaxLength(64)] string Name,
|
||||
int? DisplayOrder,
|
||||
bool IsActive = true) : IRequest<MerchantCategoryDto>;
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 新建商户合同。
|
||||
/// </summary>
|
||||
public sealed record CreateMerchantContractCommand(
|
||||
[property: Required] long MerchantId,
|
||||
[property: Required, MaxLength(64)] string ContractNumber,
|
||||
DateTime StartDate,
|
||||
DateTime EndDate,
|
||||
[property: Required, MaxLength(512)] string FileUrl) : IRequest<MerchantContractDto>;
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 删除商户类目。
|
||||
/// </summary>
|
||||
public sealed record DeleteMerchantCategoryCommand([property: Required] long CategoryId) : IRequest<bool>;
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 调整类目排序。
|
||||
/// </summary>
|
||||
public sealed record ReorderMerchantCategoriesCommand(
|
||||
[property: Required, MinLength(1)] IReadOnlyList<MerchantCategoryOrderItem> Items) : IRequest<bool>;
|
||||
|
||||
/// <summary>
|
||||
/// 类目排序条目。
|
||||
/// </summary>
|
||||
public sealed record MerchantCategoryOrderItem(
|
||||
[property: Required] long CategoryId,
|
||||
[property: Range(-1000, 100000)] int DisplayOrder);
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 审核商户入驻。
|
||||
/// </summary>
|
||||
public sealed record ReviewMerchantCommand(
|
||||
[property: Required] long MerchantId,
|
||||
bool Approve,
|
||||
string? Remarks) : IRequest<MerchantDto>;
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 审核商户证照。
|
||||
/// </summary>
|
||||
public sealed record ReviewMerchantDocumentCommand(
|
||||
[property: Required] long MerchantId,
|
||||
[property: Required] long DocumentId,
|
||||
bool Approve,
|
||||
string? Remarks) : IRequest<MerchantDocumentDto>;
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 更新合同状态。
|
||||
/// </summary>
|
||||
public sealed record UpdateMerchantContractStatusCommand(
|
||||
[property: Required] long MerchantId,
|
||||
[property: Required] long ContractId,
|
||||
[property: Required] ContractStatus Status,
|
||||
DateTime? SignedAt,
|
||||
string? Reason) : IRequest<MerchantContractDto>;
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Shared.Abstractions.Serialization;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// 商户审核日志 DTO。
|
||||
/// </summary>
|
||||
public sealed class MerchantAuditLogDto
|
||||
{
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long Id { get; init; }
|
||||
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long MerchantId { get; init; }
|
||||
|
||||
public MerchantAuditAction Action { get; init; }
|
||||
|
||||
public string Title { get; init; } = string.Empty;
|
||||
|
||||
public string? Description { get; init; }
|
||||
|
||||
public string? OperatorName { get; init; }
|
||||
|
||||
public DateTime CreatedAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// 商户类目 DTO。
|
||||
/// </summary>
|
||||
public sealed record MerchantCategoryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 类目标识。
|
||||
/// </summary>
|
||||
public long Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 类目名称。
|
||||
/// </summary>
|
||||
public string Name { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 显示顺序。
|
||||
/// </summary>
|
||||
public int DisplayOrder { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用。
|
||||
/// </summary>
|
||||
public bool IsActive { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间。
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Shared.Abstractions.Serialization;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// 商户合同 DTO。
|
||||
/// </summary>
|
||||
public sealed class MerchantContractDto
|
||||
{
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long Id { get; init; }
|
||||
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long MerchantId { get; init; }
|
||||
|
||||
public string ContractNumber { get; init; } = string.Empty;
|
||||
|
||||
public ContractStatus Status { get; init; }
|
||||
|
||||
public DateTime StartDate { get; init; }
|
||||
|
||||
public DateTime EndDate { get; init; }
|
||||
|
||||
public string FileUrl { get; init; } = string.Empty;
|
||||
|
||||
public DateTime? SignedAt { get; init; }
|
||||
|
||||
public DateTime? TerminatedAt { get; init; }
|
||||
|
||||
public string? TerminationReason { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// 商户详情 DTO。
|
||||
/// </summary>
|
||||
public sealed class MerchantDetailDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 基础信息。
|
||||
/// </summary>
|
||||
public MerchantDto Merchant { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 证照列表。
|
||||
/// </summary>
|
||||
public IReadOnlyList<MerchantDocumentDto> Documents { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 合同列表。
|
||||
/// </summary>
|
||||
public IReadOnlyList<MerchantContractDto> Contracts { get; init; } = [];
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Shared.Abstractions.Serialization;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// 商户证照 DTO。
|
||||
/// </summary>
|
||||
public sealed class MerchantDocumentDto
|
||||
{
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long Id { get; init; }
|
||||
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long MerchantId { get; init; }
|
||||
|
||||
public MerchantDocumentType DocumentType { get; init; }
|
||||
|
||||
public MerchantDocumentStatus Status { get; init; }
|
||||
|
||||
public string FileUrl { get; init; } = string.Empty;
|
||||
|
||||
public string? DocumentNumber { get; init; }
|
||||
|
||||
public DateTime? IssuedAt { get; init; }
|
||||
|
||||
public DateTime? ExpiresAt { get; init; }
|
||||
|
||||
public string? Remarks { get; init; }
|
||||
|
||||
public DateTime CreatedAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 处理证照上传。
|
||||
/// </summary>
|
||||
public sealed class AddMerchantDocumentCommandHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
ITenantProvider tenantProvider,
|
||||
IIdGenerator idGenerator,
|
||||
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)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
|
||||
|
||||
var document = new MerchantDocument
|
||||
{
|
||||
Id = _idGenerator.NextId(),
|
||||
MerchantId = merchant.Id,
|
||||
DocumentType = request.DocumentType,
|
||||
Status = MerchantDocumentStatus.Pending,
|
||||
FileUrl = request.FileUrl.Trim(),
|
||||
DocumentNumber = request.DocumentNumber?.Trim(),
|
||||
IssuedAt = request.IssuedAt,
|
||||
ExpiresAt = request.ExpiresAt
|
||||
};
|
||||
|
||||
await _merchantRepository.AddDocumentAsync(document, cancellationToken);
|
||||
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
|
||||
{
|
||||
TenantId = tenantId,
|
||||
MerchantId = merchant.Id,
|
||||
Action = MerchantAuditAction.DocumentUploaded,
|
||||
Title = "上传证照",
|
||||
Description = $"类型:{request.DocumentType}",
|
||||
OperatorId = ResolveOperatorId(),
|
||||
OperatorName = ResolveOperatorName()
|
||||
}, cancellationToken);
|
||||
|
||||
await _merchantRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return MerchantMapping.ToDto(document);
|
||||
}
|
||||
|
||||
private long? ResolveOperatorId()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? null : id;
|
||||
}
|
||||
|
||||
private string ResolveOperatorName()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? "system" : $"user:{id}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Linq;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 创建类目处理器。
|
||||
/// </summary>
|
||||
public sealed class CreateMerchantCategoryCommandHandler(
|
||||
IMerchantCategoryRepository categoryRepository,
|
||||
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();
|
||||
var normalizedName = request.Name.Trim();
|
||||
|
||||
if (await _categoryRepository.ExistsAsync(normalizedName, tenantId, cancellationToken))
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Conflict, $"类目“{normalizedName}”已存在");
|
||||
}
|
||||
|
||||
var categories = await _categoryRepository.ListAsync(tenantId, cancellationToken);
|
||||
var targetOrder = request.DisplayOrder ?? (categories.Count == 0 ? 1 : categories.Max(x => x.DisplayOrder) + 1);
|
||||
|
||||
var entity = new MerchantCategory
|
||||
{
|
||||
Name = normalizedName,
|
||||
DisplayOrder = targetOrder,
|
||||
IsActive = request.IsActive
|
||||
};
|
||||
|
||||
await _categoryRepository.AddAsync(entity, cancellationToken);
|
||||
await _categoryRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return MerchantMapping.ToDto(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 创建商户合同。
|
||||
/// </summary>
|
||||
public sealed class CreateMerchantContractCommandHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
ITenantProvider tenantProvider,
|
||||
IIdGenerator idGenerator,
|
||||
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)
|
||||
{
|
||||
if (request.EndDate <= request.StartDate)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "合同结束时间必须晚于开始时间");
|
||||
}
|
||||
|
||||
var tenantId = _tenantProvider.GetCurrentTenantId();
|
||||
var merchant = await _merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
|
||||
|
||||
var contract = new MerchantContract
|
||||
{
|
||||
Id = _idGenerator.NextId(),
|
||||
MerchantId = merchant.Id,
|
||||
ContractNumber = request.ContractNumber.Trim(),
|
||||
StartDate = request.StartDate,
|
||||
EndDate = request.EndDate,
|
||||
FileUrl = request.FileUrl.Trim()
|
||||
};
|
||||
|
||||
await _merchantRepository.AddContractAsync(contract, cancellationToken);
|
||||
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
|
||||
{
|
||||
TenantId = tenantId,
|
||||
MerchantId = merchant.Id,
|
||||
Action = MerchantAuditAction.ContractUpdated,
|
||||
Title = "新增合同",
|
||||
Description = $"合同号:{contract.ContractNumber}",
|
||||
OperatorId = ResolveOperatorId(),
|
||||
OperatorName = ResolveOperatorName()
|
||||
}, cancellationToken);
|
||||
|
||||
await _merchantRepository.SaveChangesAsync(cancellationToken);
|
||||
return MerchantMapping.ToDto(contract);
|
||||
}
|
||||
|
||||
private long? ResolveOperatorId()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? null : id;
|
||||
}
|
||||
|
||||
private string ResolveOperatorName()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? "system" : $"user:{id}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 删除类目处理器。
|
||||
/// </summary>
|
||||
public sealed class DeleteMerchantCategoryCommandHandler(
|
||||
IMerchantCategoryRepository categoryRepository,
|
||||
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);
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
await _categoryRepository.RemoveAsync(existing, cancellationToken);
|
||||
await _categoryRepository.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Linq;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 读取商户审核日志。
|
||||
/// </summary>
|
||||
public sealed class GetMerchantAuditLogsQueryHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
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);
|
||||
var total = logs.Count;
|
||||
var paged = logs
|
||||
.Skip((request.Page - 1) * request.PageSize)
|
||||
.Take(request.PageSize)
|
||||
.Select(MerchantMapping.ToDto)
|
||||
.ToList();
|
||||
|
||||
return new PagedResult<MerchantAuditLogDto>(paged, request.Page, request.PageSize, total);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 读取可选类目。
|
||||
/// </summary>
|
||||
public sealed class GetMerchantCategoriesQueryHandler(
|
||||
IMerchantCategoryRepository categoryRepository,
|
||||
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);
|
||||
|
||||
return categories
|
||||
.Where(x => x.IsActive)
|
||||
.Select(x => x.Name.Trim())
|
||||
.Where(x => x.Length > 0)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 查询合同列表。
|
||||
/// </summary>
|
||||
public sealed class GetMerchantContractsQueryHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
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)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
|
||||
|
||||
var contracts = await _merchantRepository.GetContractsAsync(request.MerchantId, tenantId, cancellationToken);
|
||||
return MerchantMapping.ToContractDtos(contracts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 商户详情处理器。
|
||||
/// </summary>
|
||||
public sealed class GetMerchantDetailQueryHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
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)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
|
||||
|
||||
var documents = await _merchantRepository.GetDocumentsAsync(request.MerchantId, tenantId, cancellationToken);
|
||||
var contracts = await _merchantRepository.GetContractsAsync(request.MerchantId, tenantId, cancellationToken);
|
||||
|
||||
return new MerchantDetailDto
|
||||
{
|
||||
Merchant = MerchantMapping.ToDto(merchant),
|
||||
Documents = MerchantMapping.ToDocumentDtos(documents),
|
||||
Contracts = MerchantMapping.ToContractDtos(contracts)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 查询证照列表。
|
||||
/// </summary>
|
||||
public sealed class GetMerchantDocumentsQueryHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
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)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
|
||||
|
||||
var documents = await _merchantRepository.GetDocumentsAsync(request.MerchantId, tenantId, cancellationToken);
|
||||
return MerchantMapping.ToDocumentDtos(documents);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 列出类目。
|
||||
/// </summary>
|
||||
public sealed class ListMerchantCategoriesQueryHandler(
|
||||
IMerchantCategoryRepository categoryRepository,
|
||||
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);
|
||||
return MerchantMapping.ToCategoryDtos(categories);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Linq;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 类目排序处理器。
|
||||
/// </summary>
|
||||
public sealed class ReorderMerchantCategoriesCommandHandler(
|
||||
IMerchantCategoryRepository categoryRepository,
|
||||
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);
|
||||
var map = categories.ToDictionary(x => x.Id);
|
||||
|
||||
foreach (var item in request.Items)
|
||||
{
|
||||
if (!map.TryGetValue(item.CategoryId, out var category))
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.NotFound, $"类目 {item.CategoryId} 不存在");
|
||||
}
|
||||
|
||||
category.DisplayOrder = item.DisplayOrder;
|
||||
}
|
||||
|
||||
await _categoryRepository.UpdateRangeAsync(map.Values, cancellationToken);
|
||||
await _categoryRepository.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 商户审核处理器。
|
||||
/// </summary>
|
||||
public sealed class ReviewMerchantCommandHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
ITenantProvider tenantProvider,
|
||||
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)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
|
||||
|
||||
if (request.Approve && merchant.Status == MerchantStatus.Approved)
|
||||
{
|
||||
return MerchantMapping.ToDto(merchant);
|
||||
}
|
||||
|
||||
var previousStatus = merchant.Status;
|
||||
merchant.Status = request.Approve ? MerchantStatus.Approved : MerchantStatus.Rejected;
|
||||
merchant.ReviewRemarks = request.Remarks;
|
||||
merchant.LastReviewedAt = DateTime.UtcNow;
|
||||
if (request.Approve && merchant.JoinedAt == null)
|
||||
{
|
||||
merchant.JoinedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await _merchantRepository.UpdateMerchantAsync(merchant, cancellationToken);
|
||||
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
|
||||
{
|
||||
TenantId = tenantId,
|
||||
MerchantId = merchant.Id,
|
||||
Action = MerchantAuditAction.MerchantReviewed,
|
||||
Title = request.Approve ? "商户审核通过" : "商户审核驳回",
|
||||
Description = request.Remarks,
|
||||
OperatorId = ResolveOperatorId(),
|
||||
OperatorName = ResolveOperatorName()
|
||||
}, cancellationToken);
|
||||
await _merchantRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return MerchantMapping.ToDto(merchant);
|
||||
}
|
||||
|
||||
private long? ResolveOperatorId()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? null : id;
|
||||
}
|
||||
|
||||
private string ResolveOperatorName()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? "system" : $"user:{id}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 审核证照处理器。
|
||||
/// </summary>
|
||||
public sealed class ReviewMerchantDocumentCommandHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
ITenantProvider tenantProvider,
|
||||
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)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "证照不存在");
|
||||
|
||||
var targetStatus = request.Approve ? MerchantDocumentStatus.Approved : MerchantDocumentStatus.Rejected;
|
||||
if (document.Status == targetStatus && document.Remarks == request.Remarks)
|
||||
{
|
||||
return MerchantMapping.ToDto(document);
|
||||
}
|
||||
|
||||
document.Status = targetStatus;
|
||||
document.Remarks = request.Remarks;
|
||||
|
||||
await _merchantRepository.UpdateDocumentAsync(document, cancellationToken);
|
||||
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
|
||||
{
|
||||
TenantId = tenantId,
|
||||
MerchantId = document.MerchantId,
|
||||
Action = MerchantAuditAction.DocumentReviewed,
|
||||
Title = request.Approve ? "证照审核通过" : "证照审核驳回",
|
||||
Description = request.Remarks,
|
||||
OperatorId = ResolveOperatorId(),
|
||||
OperatorName = ResolveOperatorName()
|
||||
}, cancellationToken);
|
||||
await _merchantRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return MerchantMapping.ToDto(document);
|
||||
}
|
||||
|
||||
private long? ResolveOperatorId()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? null : id;
|
||||
}
|
||||
|
||||
private string ResolveOperatorName()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? "system" : $"user:{id}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Commands;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 更新合同状态处理器。
|
||||
/// </summary>
|
||||
public sealed class UpdateMerchantContractStatusCommandHandler(
|
||||
IMerchantRepository merchantRepository,
|
||||
ITenantProvider tenantProvider,
|
||||
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)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "合同不存在");
|
||||
|
||||
if (request.Status == ContractStatus.Active)
|
||||
{
|
||||
contract.Status = ContractStatus.Active;
|
||||
contract.SignedAt = request.SignedAt ?? DateTime.UtcNow;
|
||||
}
|
||||
else if (request.Status == ContractStatus.Terminated)
|
||||
{
|
||||
contract.Status = ContractStatus.Terminated;
|
||||
contract.TerminatedAt = DateTime.UtcNow;
|
||||
contract.TerminationReason = request.Reason;
|
||||
}
|
||||
else
|
||||
{
|
||||
contract.Status = request.Status;
|
||||
}
|
||||
|
||||
await _merchantRepository.UpdateContractAsync(contract, cancellationToken);
|
||||
await _merchantRepository.AddAuditLogAsync(new MerchantAuditLog
|
||||
{
|
||||
TenantId = tenantId,
|
||||
MerchantId = contract.MerchantId,
|
||||
Action = MerchantAuditAction.ContractStatusChanged,
|
||||
Title = $"合同状态变更为 {request.Status}",
|
||||
Description = request.Reason,
|
||||
OperatorId = ResolveOperatorId(),
|
||||
OperatorName = ResolveOperatorName()
|
||||
}, cancellationToken);
|
||||
|
||||
await _merchantRepository.SaveChangesAsync(cancellationToken);
|
||||
return MerchantMapping.ToDto(contract);
|
||||
}
|
||||
|
||||
private long? ResolveOperatorId()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? null : id;
|
||||
}
|
||||
|
||||
private string ResolveOperatorName()
|
||||
{
|
||||
var id = _currentUserAccessor.UserId;
|
||||
return id == 0 ? "system" : $"user:{id}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants;
|
||||
|
||||
/// <summary>
|
||||
/// 商户 DTO 映射工具。
|
||||
/// </summary>
|
||||
internal static class MerchantMapping
|
||||
{
|
||||
public static MerchantDto ToDto(Merchant merchant) => new()
|
||||
{
|
||||
Id = merchant.Id,
|
||||
TenantId = merchant.TenantId,
|
||||
BrandName = merchant.BrandName,
|
||||
BrandAlias = merchant.BrandAlias,
|
||||
LogoUrl = merchant.LogoUrl,
|
||||
Category = merchant.Category,
|
||||
ContactPhone = merchant.ContactPhone,
|
||||
ContactEmail = merchant.ContactEmail,
|
||||
Status = merchant.Status,
|
||||
JoinedAt = merchant.JoinedAt,
|
||||
CreatedAt = merchant.CreatedAt
|
||||
};
|
||||
|
||||
public static MerchantDocumentDto ToDto(MerchantDocument document) => new()
|
||||
{
|
||||
Id = document.Id,
|
||||
MerchantId = document.MerchantId,
|
||||
DocumentType = document.DocumentType,
|
||||
Status = document.Status,
|
||||
FileUrl = document.FileUrl,
|
||||
DocumentNumber = document.DocumentNumber,
|
||||
IssuedAt = document.IssuedAt,
|
||||
ExpiresAt = document.ExpiresAt,
|
||||
Remarks = document.Remarks,
|
||||
CreatedAt = document.CreatedAt
|
||||
};
|
||||
|
||||
public static MerchantContractDto ToDto(MerchantContract contract) => new()
|
||||
{
|
||||
Id = contract.Id,
|
||||
MerchantId = contract.MerchantId,
|
||||
ContractNumber = contract.ContractNumber,
|
||||
Status = contract.Status,
|
||||
StartDate = contract.StartDate,
|
||||
EndDate = contract.EndDate,
|
||||
FileUrl = contract.FileUrl,
|
||||
SignedAt = contract.SignedAt,
|
||||
TerminatedAt = contract.TerminatedAt,
|
||||
TerminationReason = contract.TerminationReason
|
||||
};
|
||||
|
||||
public static MerchantAuditLogDto ToDto(MerchantAuditLog log) => new()
|
||||
{
|
||||
Id = log.Id,
|
||||
MerchantId = log.MerchantId,
|
||||
Action = log.Action,
|
||||
Title = log.Title,
|
||||
Description = log.Description,
|
||||
OperatorName = log.OperatorName,
|
||||
CreatedAt = log.CreatedAt
|
||||
};
|
||||
|
||||
public static MerchantCategoryDto ToDto(MerchantCategory category) => new()
|
||||
{
|
||||
Id = category.Id,
|
||||
Name = category.Name,
|
||||
DisplayOrder = category.DisplayOrder,
|
||||
IsActive = category.IsActive,
|
||||
CreatedAt = category.CreatedAt
|
||||
};
|
||||
|
||||
public static IReadOnlyList<MerchantDocumentDto> ToDocumentDtos(IEnumerable<MerchantDocument> documents)
|
||||
=> documents.Select(ToDto).ToList();
|
||||
|
||||
public static IReadOnlyList<MerchantContractDto> ToContractDtos(IEnumerable<MerchantContract> contracts)
|
||||
=> contracts.Select(ToDto).ToList();
|
||||
|
||||
public static IReadOnlyList<MerchantCategoryDto> ToCategoryDtos(IEnumerable<MerchantCategory> categories)
|
||||
=> categories.Select(ToDto).ToList();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 商户审核日志查询。
|
||||
/// </summary>
|
||||
public sealed record GetMerchantAuditLogsQuery(
|
||||
long MerchantId,
|
||||
int Page = 1,
|
||||
int PageSize = 20) : IRequest<PagedResult<MerchantAuditLogDto>>;
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 获取商户可选类目。
|
||||
/// </summary>
|
||||
public sealed record GetMerchantCategoriesQuery() : IRequest<IReadOnlyList<string>>;
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 查询商户合同。
|
||||
/// </summary>
|
||||
public sealed record GetMerchantContractsQuery(long MerchantId) : IRequest<IReadOnlyList<MerchantContractDto>>;
|
||||
@@ -0,0 +1,9 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 商户详情查询。
|
||||
/// </summary>
|
||||
public sealed record GetMerchantDetailQuery(long MerchantId) : IRequest<MerchantDetailDto>;
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 查询商户证照。
|
||||
/// </summary>
|
||||
public sealed record GetMerchantDocumentsQuery(long MerchantId) : IRequest<IReadOnlyList<MerchantDocumentDto>>;
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.Merchants.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.Merchants.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 管理端获取完整类目列表。
|
||||
/// </summary>
|
||||
public sealed record ListMerchantCategoriesQuery() : IRequest<IReadOnlyList<MerchantCategoryDto>>;
|
||||
Reference in New Issue
Block a user