- Fix IsDeleted/CreatedAt/BusinessName private field access in LINQ queries
using EF.Property<T>() instead of public computed properties (which are
Ignored in EF config due to DDD pattern)
- Fix Shop.MerchantId private field in GroupBy shop count query
- Split merchant list query into 2 steps (fetch + batch shop counts)
to avoid untranslatable subquery in Join+Select
- Fix BFF SuperAdminController: remove duplicate auth header setting
(AuthForwardingHandler already reads bff_session cookie)
- Fix frontend DTO field names to match API response (ShopsCount, Type)
- Fix frontend response format handling for direct {items} without {data} wrapper
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
80 lines
2.8 KiB
C#
80 lines
2.8 KiB
C#
// EN: Query to get merchant details for admin.
|
|
// VI: Query để lấy chi tiết merchant cho admin.
|
|
|
|
using MediatR;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using MerchantService.Domain.Exceptions;
|
|
using MerchantService.Infrastructure;
|
|
|
|
namespace MerchantService.API.Application.Queries.Admin;
|
|
|
|
/// <summary>
|
|
/// EN: Query to get detailed merchant information (Admin only).
|
|
/// VI: Query để lấy thông tin chi tiết merchant (chỉ Admin).
|
|
/// </summary>
|
|
public record GetMerchantDetailQuery(Guid MerchantId) : IRequest<AdminMerchantDetailDto>;
|
|
|
|
/// <summary>
|
|
/// EN: Handler for GetMerchantDetailQuery.
|
|
/// VI: Handler cho GetMerchantDetailQuery.
|
|
/// </summary>
|
|
public class GetMerchantDetailQueryHandler : IRequestHandler<GetMerchantDetailQuery, AdminMerchantDetailDto>
|
|
{
|
|
private readonly MerchantServiceContext _context;
|
|
|
|
public GetMerchantDetailQueryHandler(MerchantServiceContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
public async Task<AdminMerchantDetailDto> Handle(
|
|
GetMerchantDetailQuery request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var merchant = await _context.Merchants
|
|
.AsNoTracking()
|
|
.Where(m => m.Id == request.MerchantId && !EF.Property<bool>(m, "_isDeleted"))
|
|
.FirstOrDefaultAsync(cancellationToken)
|
|
?? throw new DomainException($"Merchant {request.MerchantId} not found");
|
|
|
|
var shopsCount = await _context.Shops
|
|
.CountAsync(s => s.MerchantId == request.MerchantId && !EF.Property<bool>(s, "_isDeleted"), cancellationToken);
|
|
|
|
var staffCount = await _context.MerchantStaff
|
|
.CountAsync(s => s.MerchantId == request.MerchantId, cancellationToken);
|
|
|
|
var businessInfo = merchant.BusinessInfo != null
|
|
? new AdminBusinessInfoDto(
|
|
merchant.BusinessInfo.TaxId,
|
|
merchant.BusinessInfo.BusinessLicenseNumber,
|
|
merchant.BusinessInfo.CompanyRegistrationNumber,
|
|
null,
|
|
null,
|
|
null)
|
|
: null;
|
|
|
|
var settlementConfig = merchant.SettlementConfig != null
|
|
? new AdminSettlementConfigDto(
|
|
merchant.SettlementConfig.CommissionRate,
|
|
merchant.SettlementConfig.SettlementCycleId.ToString(),
|
|
merchant.SettlementConfig.BankAccount?.ToString())
|
|
: null;
|
|
|
|
return new AdminMerchantDetailDto(
|
|
merchant.Id,
|
|
merchant.UserId,
|
|
merchant.BusinessName,
|
|
merchant.Type.Name,
|
|
merchant.Status.Name,
|
|
merchant.VerificationStatus.Name,
|
|
businessInfo,
|
|
settlementConfig,
|
|
shopsCount,
|
|
staffCount,
|
|
merchant.CreatedAt,
|
|
merchant.UpdatedAt,
|
|
merchant.VerifiedAt,
|
|
merchant.VerifiedBy);
|
|
}
|
|
}
|