fix: 地址簿管理端可查全部,修复 SqlSugar 条件翻译

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-07-16 12:30:30 +08:00
parent 9a48ec1a63
commit 1cf55b2669
3 changed files with 59 additions and 29 deletions

View File

@ -13,6 +13,12 @@ public class CustomerSenderAddressPaginatedInput
[Newtonsoft.Json.JsonProperty("pageSize")]
public int PageSize { get; set; } = 30;
/// <summary>
/// 客户 ID(管理端可选;不传则查全部)。
/// </summary>
[Newtonsoft.Json.JsonProperty("customerId")]
public int? CustomerId { get; set; }
/// <summary>
/// 地址类型:all / sender / return / receiver。
/// </summary>
@ -31,6 +37,11 @@ public class CustomerSenderAddressPaginatedInput
/// </summary>
public class CreateCustomerSenderAddressInput
{
/// <summary>
/// 客户 ID(管理端代操作必传;客户门户可省略)。
/// </summary>
public int? CustomerId { get; set; }
/// <summary>
/// 地址类型:sender 发件 / return 退件 / receiver 收件。
/// </summary>

View File

@ -17,26 +17,27 @@ public partial class OrderService
/// <summary>
/// 客户地址分页列表(发件/退件/收件)。
/// 管理端未传 customerId 时查询全部;客户门户仅查自身。
/// </summary>
[HttpPost("/order/sender-address/list")]
public async Task<OmsPageResult<CustomerSenderAddressOutput>> GetSenderAddressListAsync(
[FromBody] CustomerSenderAddressPaginatedInput input)
{
var customer = await OmsSessionHelper.ResolveSessionCustomerAsync(CustomerRepository, CurrentUser);
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
input.CustomerId);
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
var predicate = BuildSenderAddressPredicate(customer.Id, input);
var predicate = BuildSenderAddressPredicate(customerId, input);
var entities = await CustomerSenderAddressRepository.GetPagedListAsync(
// 避免 Fake GetPagedListAsync(sorting) 丢失 Where / SqlSugar 错误翻译表达式
var (entities, total) = await RepositoryPageHelper.GetPageAsync(
CustomerSenderAddressRepository,
predicate,
pageIndex,
pageSize,
new Dictionary<string, bool>
{
[nameof(CustomerSenderAddress.IsDefault)] = false,
[nameof(CustomerSenderAddress.Id)] = false
});
var total = await CustomerSenderAddressRepository.CountAsync(predicate);
q => q.OrderByDescending(x => x.IsDefault).ThenByDescending(x => x.Id));
var countryMap = await LoadCountryCodeMapAsync(entities.Select(x => x.Country).Where(x => x.HasValue).Select(x => x!.Value));
return new OmsPageResult<CustomerSenderAddressOutput>
@ -50,9 +51,11 @@ public partial class OrderService
/// 客户地址详情。
/// </summary>
[HttpGet("/order/sender-address/detail")]
public async Task<CustomerSenderAddressOutput> GetSenderAddressDetailAsync([FromQuery] int id)
public async Task<CustomerSenderAddressOutput> GetSenderAddressDetailAsync(
[FromQuery] int id,
[FromQuery] int? customerId = null)
{
var entity = await GetOwnedSenderAddressOrThrowAsync(id);
var entity = await GetOwnedSenderAddressOrThrowAsync(id, customerId);
var countryMap = await LoadCountryCodeMapAsync(entity.Country.HasValue ? [entity.Country.Value] : []);
return MapSenderAddressOutput(entity, countryMap);
}
@ -63,19 +66,22 @@ public partial class OrderService
[HttpPost("/order/sender-address/create")]
public async Task<object> CreateSenderAddressAsync([FromBody] CreateCustomerSenderAddressInput input)
{
var customer = await OmsSessionHelper.ResolveSessionCustomerAsync(CustomerRepository, CurrentUser);
var customerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
CustomerRepository,
CurrentUser,
input.CustomerId);
var addressType = NormalizeAddressTypeOrThrow(input.AddressType);
ValidateSenderAddressInput(input);
var countryId = await ResolveSenderCountryIdAsync(input.CountryCode);
if (input.IsDefault)
{
await CustomerSenderAddressRepository.ClearDefaultAsync(customer.Id, addressType);
await CustomerSenderAddressRepository.ClearDefaultAsync(customerId, addressType);
}
var entity = new CustomerSenderAddress
{
CustomerId = customer.Id,
CustomerId = customerId,
AddressType = addressType,
AddressName = TrimOrNull(input.AddressName),
SenderName = input.SenderName.Trim(),
@ -104,7 +110,7 @@ public partial class OrderService
[HttpPost("/order/sender-address/update")]
public async Task UpdateSenderAddressAsync([FromBody] UpdateCustomerSenderAddressInput input)
{
var entity = await GetOwnedSenderAddressOrThrowAsync(input.Id);
var entity = await GetOwnedSenderAddressOrThrowAsync(input.Id, input.CustomerId);
var addressType = NormalizeAddressTypeOrThrow(input.AddressType);
ValidateSenderAddressInput(input);
var countryId = await ResolveSenderCountryIdAsync(input.CountryCode);
@ -140,7 +146,7 @@ public partial class OrderService
[HttpPost("/order/sender-address/delete")]
public async Task DeleteSenderAddressAsync([FromBody] IdInput input)
{
var entity = await GetOwnedSenderAddressOrThrowAsync(input.Id);
var entity = await GetOwnedSenderAddressOrThrowAsync(input.Id, null);
await CustomerSenderAddressRepository.DeleteAsync(entity);
}
@ -150,7 +156,7 @@ public partial class OrderService
[HttpPost("/order/sender-address/set-default")]
public async Task SetDefaultSenderAddressAsync([FromBody] IdInput input)
{
var entity = await GetOwnedSenderAddressOrThrowAsync(input.Id);
var entity = await GetOwnedSenderAddressOrThrowAsync(input.Id, null);
var addressType = string.IsNullOrWhiteSpace(entity.AddressType)
? CustomerAddressTypeCodes.Sender
: entity.AddressType;
@ -159,10 +165,17 @@ public partial class OrderService
await CustomerSenderAddressRepository.UpdateAsync(entity);
}
private async Task<CustomerSenderAddress> GetOwnedSenderAddressOrThrowAsync(int id)
private async Task<CustomerSenderAddress> GetOwnedSenderAddressOrThrowAsync(int id, int? requestedCustomerId)
{
var customer = await OmsSessionHelper.ResolveSessionCustomerAsync(CustomerRepository, CurrentUser);
var entity = await CustomerSenderAddressRepository.GetOwnedAsync(id, customer.Id);
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
requestedCustomerId);
var (hasCustomerFilter, customerIdValue) = WarehouseCustomerHelper.ToCustomerFilter(customerId);
var entity = hasCustomerFilter
? await CustomerSenderAddressRepository.GetOwnedAsync(id, customerIdValue)
: await CustomerSenderAddressRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
{
throw new BusinessException("地址不存在");
@ -204,24 +217,28 @@ public partial class OrderService
}
private static Expression<Func<CustomerSenderAddress, bool>> BuildSenderAddressPredicate(
int customerId,
int? customerId,
CustomerSenderAddressPaginatedInput input)
{
var (hasCustomerFilter, customerIdValue) = WarehouseCustomerHelper.ToCustomerFilter(customerId);
var keyword = input.Keyword?.Trim();
var hasKeyword = !string.IsNullOrWhiteSpace(keyword);
var onlyDefault = input.OnlyDefault;
var addressType = input.AddressType?.Trim();
var filterByType = !string.IsNullOrWhiteSpace(addressType)
&& !string.Equals(addressType, "all", StringComparison.OrdinalIgnoreCase);
var addressTypeValue = filterByType ? addressType! : string.Empty;
// 布尔/关键字先算成局部变量;避免 SqlSugar 翻译 IsNullOrWhiteSpace / ?? / HasValue 生成非法 SQL
return x =>
x.CustomerId == customerId
&& (!filterByType || x.AddressType == addressType)
(!hasCustomerFilter || x.CustomerId == customerIdValue)
&& (!filterByType || x.AddressType == addressTypeValue)
&& (!onlyDefault || x.IsDefault == 1)
&& (string.IsNullOrWhiteSpace(keyword)
|| (x.AddressName ?? string.Empty).Contains(keyword)
|| x.SenderName.Contains(keyword)
|| (x.Phone ?? string.Empty).Contains(keyword)
|| x.StreetAddress1.Contains(keyword));
&& (!hasKeyword
|| (x.AddressName != null && x.AddressName.Contains(keyword!))
|| x.SenderName.Contains(keyword!)
|| (x.Phone != null && x.Phone.Contains(keyword!))
|| x.StreetAddress1.Contains(keyword!));
}
private async Task<Dictionary<int, string>> LoadCountryCodeMapAsync(IEnumerable<int> countryIds)

View File

@ -19,11 +19,13 @@ public class CustomerSenderAddressRepository : OmsSqlSugarRepository<CustomerSen
CancellationToken cancellationToken = default)
{
var type = addressType.Trim();
var hasExcludeId = excludeId.HasValue;
var excludeIdValue = excludeId.GetValueOrDefault();
var list = await GetListAsync(
x => x.CustomerId == customerId
&& x.AddressType == type
&& x.IsDefault == 1
&& (!excludeId.HasValue || x.Id != excludeId.Value),
&& (!hasExcludeId || x.Id != excludeIdValue),
cancellationToken: cancellationToken);
if (list.Count == 0)
{