admin/src/Oms.Application/Services/System/WarehouseService.cs
zzh b17e6639a4
All checks were successful
Build and Deploy / deploy (push) Successful in 1m3s
fix: 主数据新增兼容软删唯一键,避免 Duplicate entry
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-05 11:53:08 +08:00

184 lines
7.3 KiB
C#

using System.Linq.Expressions;
using Fake.Application;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Shared;
using Oms.Application.Dtos.System;
using Oms.Application.Shared;
using Oms.Domain.SystemAggregate.Consts;
using Oms.Domain.SystemAggregate.Entities;
using Oms.Domain.SystemAggregate.Repositories;
namespace Oms.Application.Services.System;
/// <summary>
/// 仓库 API 服务。
/// </summary>
[ApiExplorerSettings(GroupName = "OMS-System")]
public class WarehouseService : ApplicationService
{
private IWarehouseAddressRepository WarehouseAddressRepository => LazyServiceProvider.GetRequiredService<IWarehouseAddressRepository>();
private OmsRbacUserDisplayNameResolver UserDisplayNameResolver =>
LazyServiceProvider.GetRequiredService<OmsRbacUserDisplayNameResolver>();
/// <summary>
/// 查询仓库列表。
/// </summary>
/// <param name="input">入参:仓库分页查询条件。</param>
/// <returns>仓库分页结果,包含列表数据和总记录数。</returns>
[HttpGet("/system/warehouse/list")]
public async Task<OmsPageResult<WarehousePaginatedOutput>> GetPaginatedListAsync([FromQuery] WarehousePaginatedInput input)
{
var predicate = BuildPaginatedPredicate(input);
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
var entities = await WarehouseAddressRepository.GetPagedListAsync(
predicate,
pageIndex,
pageSize,
new Dictionary<string, bool> { [nameof(WarehouseAddress.UpdateTime)] = false, [nameof(WarehouseAddress.Id)] = false });
var totalCount = await WarehouseAddressRepository.CountAsync(predicate);
var items = entities.Select(entity =>
{
var output = ObjectMapper.Map<WarehouseAddress, WarehousePaginatedOutput>(entity);
output.WarehouseTypeName = OmsDocHelper.GetWarehouseTypeName(entity.WarehouseType);
output.UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime);
return output;
}).ToList();
return new OmsPageResult<WarehousePaginatedOutput>
{
Items = items,
Total = totalCount
};
}
/// <summary>
/// 查询仓库详情。
/// </summary>
/// <param name="id">入参:目标主键。</param>
/// <returns>仓库详情。</returns>
[HttpGet("/system/warehouse/detail")]
public async Task<WarehouseOutput> GetByIdAsync([FromQuery] int id)
{
var entity = await GetWarehouseOrThrowAsync(id);
var output = ObjectMapper.Map<WarehouseAddress, WarehouseOutput>(entity);
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
[entity.CreateUserId, entity.UpdateUserId]);
output.CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.CreateUserId, auditUserNameMap);
output.UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.UpdateUserId, auditUserNameMap);
output.UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime);
return output;
}
/// <summary>
/// 新增仓库。
/// </summary>
/// <param name="input">入参:仓库创建参数。</param>
/// <returns>无返回体,仅完成新增仓库。</returns>
[HttpPost("/system/warehouse/create")]
public async Task CreateAsync(CreateWarehouseInput input)
{
var warehouseName = input.WarehouseName.Trim();
var duplicatedWarehouse = await WarehouseAddressRepository.GetByWarehouseNameAsync(warehouseName);
if (duplicatedWarehouse != null)
{
throw new BusinessException("仓库名称已存在");
}
var deleted = await WarehouseAddressRepository.GetByWarehouseNameIncludingDeletedAsync(warehouseName);
if (deleted != null && deleted.IsDeleted)
{
deleted.IsDeleted = false;
deleted.WarehouseName = warehouseName;
deleted.WarehouseType = input.WarehouseType;
deleted.Recipient = input.Recipient;
deleted.ContactPhone = input.ContactPhone;
deleted.ShippingAddress = input.ShippingAddress;
await WarehouseAddressRepository.UpdateAsync(deleted);
return;
}
var entity = new WarehouseAddress
{
WarehouseName = warehouseName,
WarehouseType = input.WarehouseType,
Recipient = input.Recipient,
ContactPhone = input.ContactPhone,
ShippingAddress = input.ShippingAddress,
};
await WarehouseAddressRepository.InsertAsync(entity);
}
/// <summary>
/// 更新仓库。
/// </summary>
/// <param name="input">入参:仓库更新参数。</param>
/// <returns>无返回体,仅完成更新仓库。</returns>
[HttpPost("/system/warehouse/update")]
public async Task UpdateAsync(UpdateWarehouseInput input)
{
var entity = await GetWarehouseOrThrowAsync(input.Id);
var warehouseName = input.WarehouseName.Trim();
var duplicatedWarehouse = await WarehouseAddressRepository.GetByWarehouseNameAsync(warehouseName);
if (duplicatedWarehouse != null && duplicatedWarehouse.Id != entity.Id)
{
throw new BusinessException("仓库名称已存在");
}
var softDeleted = await WarehouseAddressRepository.GetByWarehouseNameIncludingDeletedAsync(warehouseName);
if (softDeleted != null && softDeleted.IsDeleted && softDeleted.Id != entity.Id)
{
softDeleted.WarehouseName = $"{warehouseName}__deleted_{softDeleted.Id}";
await WarehouseAddressRepository.UpdateAsync(softDeleted);
}
entity.WarehouseName = warehouseName;
entity.WarehouseType = input.WarehouseType;
entity.Recipient = input.Recipient;
entity.ContactPhone = input.ContactPhone;
entity.ShippingAddress = input.ShippingAddress;
await WarehouseAddressRepository.UpdateAsync(entity);
}
/// <summary>
/// 删除仓库。
/// </summary>
/// <param name="input">入参:目标主键。</param>
/// <returns>无返回体,仅完成删除仓库。</returns>
[HttpPost("/system/warehouse/delete")]
public async Task DeleteAsync(IdInput input)
{
var entity = await GetWarehouseOrThrowAsync(input.Id);
await WarehouseAddressRepository.DeleteAsync(entity);
}
private Expression<Func<WarehouseAddress, bool>> BuildPaginatedPredicate(WarehousePaginatedInput input)
{
var keyword = input.Keyword?.Trim();
var warehouseType = input.WarehouseType?.Trim();
return warehouse =>
(string.IsNullOrWhiteSpace(warehouseType) || warehouse.WarehouseType == warehouseType) &&
(string.IsNullOrWhiteSpace(keyword) ||
warehouse.WarehouseName.Contains(keyword) ||
(warehouse.Recipient ?? string.Empty).Contains(keyword) ||
(warehouse.ContactPhone ?? string.Empty).Contains(keyword));
}
private async Task<WarehouseAddress> GetWarehouseOrThrowAsync(int id)
{
var entity = await WarehouseAddressRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
{
throw new BusinessException("仓库不存在");
}
return entity;
}
}