308 lines
10 KiB
C#
308 lines
10 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using TakeoutSaaS.Domain.Common.Enums;
|
|
using TakeoutSaaS.Domain.Merchants.Entities;
|
|
using TakeoutSaaS.Domain.Merchants.Enums;
|
|
using TakeoutSaaS.Domain.Merchants.Repositories;
|
|
using TakeoutSaaS.Infrastructure.App.Persistence;
|
|
using TakeoutSaaS.Infrastructure.Logs.Persistence;
|
|
|
|
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
|
|
|
/// <summary>
|
|
/// 商户聚合的 EF Core 仓储实现。
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 初始化仓储。
|
|
/// </remarks>
|
|
public sealed class EfMerchantRepository(TakeoutAdminDbContext context, TakeoutLogsDbContext logsContext) : IMerchantRepository
|
|
{
|
|
/// <inheritdoc />
|
|
public Task<Merchant?> FindByIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.Merchants
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.Id == merchantId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<Merchant?> FindByIdAsync(long merchantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.Merchants
|
|
.IgnoreQueryFilters()
|
|
.AsNoTracking()
|
|
.Where(x => x.Id == merchantId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<Merchant?> FindByTenantIdAsync(long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.Merchants
|
|
.IgnoreQueryFilters()
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<Merchant>> SearchAsync(long tenantId, MerchantStatus? status, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.Merchants
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId);
|
|
|
|
if (status.HasValue)
|
|
{
|
|
query = query.Where(x => x.Status == status.Value);
|
|
}
|
|
|
|
return await query
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<MerchantStaff>> GetStaffAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var staffs = await context.MerchantStaff
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
|
.OrderBy(x => x.Name)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return staffs;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<MerchantStaff>> GetStaffByStoreAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var staffs = await context.MerchantStaff
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
|
.OrderBy(x => x.Name)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return staffs;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<MerchantStaff?> FindStaffByIdAsync(long staffId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.MerchantStaff
|
|
.Where(x => x.TenantId == tenantId && x.Id == staffId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<MerchantContract>> GetContractsAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var contracts = await context.MerchantContracts
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return contracts;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<MerchantContract?> FindContractByIdAsync(long merchantId, long tenantId, long contractId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.MerchantContracts
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId && x.Id == contractId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<MerchantDocument>> GetDocumentsAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var documents = await context.MerchantDocuments
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
|
.OrderBy(x => x.CreatedAt)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return documents;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<MerchantDocument?> FindDocumentByIdAsync(long merchantId, long tenantId, long documentId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.MerchantDocuments
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId && x.Id == documentId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddMerchantAsync(Merchant merchant, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.Merchants.AddAsync(merchant, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddStaffAsync(MerchantStaff staff, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.MerchantStaff.AddAsync(staff, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddContractAsync(MerchantContract contract, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.MerchantContracts.AddAsync(contract, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateContractAsync(MerchantContract contract, CancellationToken cancellationToken = default)
|
|
{
|
|
context.MerchantContracts.Update(contract);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddDocumentAsync(MerchantDocument document, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.MerchantDocuments.AddAsync(document, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateDocumentAsync(MerchantDocument document, CancellationToken cancellationToken = default)
|
|
{
|
|
context.MerchantDocuments.Update(document);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
// 1. 保存业务库变更
|
|
await context.SaveChangesAsync(cancellationToken);
|
|
|
|
// 2. 保存日志库变更
|
|
await logsContext.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateMerchantAsync(Merchant merchant, CancellationToken cancellationToken = default)
|
|
{
|
|
context.Merchants.Update(merchant);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteMerchantAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.Merchants
|
|
.Where(x => x.TenantId == tenantId && x.Id == merchantId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
context.Merchants.Remove(existing);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteStaffAsync(long staffId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
var existing = await context.MerchantStaff
|
|
.Where(x => x.TenantId == tenantId && x.Id == staffId)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (existing == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
context.MerchantStaff.Remove(existing);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddAuditLogAsync(MerchantAuditLog log, CancellationToken cancellationToken = default)
|
|
{
|
|
return logsContext.MerchantAuditLogs.AddAsync(log, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<MerchantAuditLog>> GetAuditLogsAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
|
{
|
|
return await logsContext.MerchantAuditLogs
|
|
.IgnoreQueryFilters()
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<Merchant>> SearchAsync(
|
|
long? tenantId,
|
|
MerchantStatus? status,
|
|
OperatingMode? operatingMode,
|
|
string? keyword,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var query = context.Merchants
|
|
.IgnoreQueryFilters()
|
|
.AsNoTracking()
|
|
.AsQueryable();
|
|
|
|
if (tenantId.HasValue && tenantId.Value > 0)
|
|
{
|
|
query = query.Where(x => x.TenantId == tenantId.Value);
|
|
}
|
|
|
|
if (status.HasValue)
|
|
{
|
|
query = query.Where(x => x.Status == status.Value);
|
|
}
|
|
|
|
if (operatingMode.HasValue)
|
|
{
|
|
query = query.Where(x => x.OperatingMode == operatingMode.Value);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(keyword))
|
|
{
|
|
var normalized = keyword.Trim();
|
|
query = query.Where(x =>
|
|
EF.Functions.ILike(x.BrandName, $"%{normalized}%") ||
|
|
EF.Functions.ILike(x.BusinessLicenseNumber ?? string.Empty, $"%{normalized}%"));
|
|
}
|
|
|
|
return await query
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddChangeLogAsync(MerchantChangeLog log, CancellationToken cancellationToken = default)
|
|
{
|
|
return logsContext.MerchantChangeLogs.AddAsync(log, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<MerchantChangeLog>> GetChangeLogsAsync(
|
|
long merchantId,
|
|
long tenantId,
|
|
string? fieldName = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var query = logsContext.MerchantChangeLogs
|
|
.IgnoreQueryFilters()
|
|
.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId);
|
|
|
|
if (!string.IsNullOrWhiteSpace(fieldName))
|
|
{
|
|
query = query.Where(x => x.FieldName == fieldName);
|
|
}
|
|
|
|
return await query
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
}
|