修复管理端访问仓储与店铺接口时客户ID必填报错。

列表/汇总/详情改用 ResolveListCustomerIdAsync,管理端未传 customerId 时可查询全部数据。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-07-11 16:14:44 +08:00
parent 8000162f02
commit 36fb191f94
8 changed files with 88 additions and 57 deletions

View File

@ -43,7 +43,7 @@ public class PlatformStoreOrderService : ApplicationService
[HttpPost("/order/platform-store-order/list")]
public async Task<OmsPageResult<PlatformStoreOrderOutput>> GetListAsync(PlatformStoreOrderListInput input)
{
var customerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
input.CustomerId);
@ -95,7 +95,7 @@ public class PlatformStoreOrderService : ApplicationService
[HttpGet("/order/platform-store-order/detail")]
public async Task<PlatformStoreOrderOutput> GetDetailAsync([FromQuery] int id, [FromQuery] int? customerId = null)
{
var resolvedCustomerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
var resolvedCustomerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
customerId);
@ -121,12 +121,12 @@ public class PlatformStoreOrderService : ApplicationService
[HttpGet("/order/platform-store-order/summary")]
public async Task<PlatformStoreOrderSummaryOutput> GetSummaryAsync([FromQuery] int? customerId = null, [FromQuery] int? storeId = null)
{
var resolvedCustomerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
var resolvedCustomerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
customerId);
var orders = await StoreOrderRepository.GetListAsync(x =>
x.CustomerId == resolvedCustomerId
(!resolvedCustomerId.HasValue || x.CustomerId == resolvedCustomerId.Value)
&& (!storeId.HasValue || x.StoreId == storeId.Value));
return new PlatformStoreOrderSummaryOutput
@ -228,11 +228,12 @@ public class PlatformStoreOrderService : ApplicationService
throw new BusinessException("请选择要删除的订单");
}
var customerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
input.CustomerId);
var orders = await StoreOrderRepository.GetListAsync(x => x.CustomerId == customerId && input.Ids.Contains(x.Id));
var orders = await StoreOrderRepository.GetListAsync(x =>
(!customerId.HasValue || x.CustomerId == customerId.Value) && input.Ids.Contains(x.Id));
foreach (var order in orders)
{
var lines = await StoreOrderLineRepository.GetListAsync(x => x.StoreOrderId == order.Id);
@ -578,9 +579,11 @@ public class PlatformStoreOrderService : ApplicationService
return linked?.ServiceNo;
}
private async Task<SalesStoreOrder> GetOrderOrThrowAsync(int customerId, int id)
private async Task<SalesStoreOrder> GetOrderOrThrowAsync(int? customerId, int id)
{
var entity = await StoreOrderRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId);
var entity = customerId.HasValue
? await StoreOrderRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId.Value)
: await StoreOrderRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
{
throw new BusinessException("店铺订单不存在");
@ -589,13 +592,13 @@ public class PlatformStoreOrderService : ApplicationService
return entity;
}
private static Expression<Func<SalesStoreOrder, bool>> BuildListPredicate(int customerId, PlatformStoreOrderListInput input)
private static Expression<Func<SalesStoreOrder, bool>> BuildListPredicate(int? customerId, PlatformStoreOrderListInput input)
{
var fulfillStatus = input.FulfillStatus?.Trim();
var platformOrderNo = input.PlatformOrderNo?.Trim();
return x =>
x.CustomerId == customerId
(!customerId.HasValue || x.CustomerId == customerId.Value)
&& (!input.StoreId.HasValue || x.StoreId == input.StoreId.Value)
&& (string.IsNullOrWhiteSpace(fulfillStatus) || x.FulfillStatus == fulfillStatus)
&& (!input.IsSuspended.HasValue || x.IsSuspended == input.IsSuspended.Value)

View File

@ -28,7 +28,7 @@ public class PlatformStoreService : ApplicationService
[HttpPost("/order/platform-store/list")]
public async Task<OmsPageResult<PlatformStoreOutput>> GetListAsync(PlatformStorePageInput input)
{
var customerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
input.CustomerId);
@ -138,20 +138,23 @@ public class PlatformStoreService : ApplicationService
throw new BusinessException("请选择要删除的店铺");
}
var customerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
null);
var entities = await StoreRepository.GetListAsync(x => x.CustomerId == customerId && input.Ids.Contains(x.Id));
var entities = await StoreRepository.GetListAsync(x =>
(!customerId.HasValue || x.CustomerId == customerId.Value) && input.Ids.Contains(x.Id));
foreach (var entity in entities)
{
await StoreRepository.DeleteAsync(entity);
}
}
private async Task<SalesStore> GetStoreOrThrowAsync(int customerId, int id)
private async Task<SalesStore> GetStoreOrThrowAsync(int? customerId, int id)
{
var entity = await StoreRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId);
var entity = customerId.HasValue
? await StoreRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId.Value)
: await StoreRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
{
throw new BusinessException("店铺不存在");
@ -160,7 +163,7 @@ public class PlatformStoreService : ApplicationService
return entity;
}
private static Expression<Func<SalesStore, bool>> BuildListPredicate(int customerId, PlatformStorePageInput input)
private static Expression<Func<SalesStore, bool>> BuildListPredicate(int? customerId, PlatformStorePageInput input)
{
var platformCode = input.PlatformCode?.Trim();
var nickname = input.StoreNickname?.Trim();
@ -169,7 +172,7 @@ public class PlatformStoreService : ApplicationService
var within7Days = now.AddDays(7);
return x =>
x.CustomerId == customerId
(!customerId.HasValue || x.CustomerId == customerId.Value)
&& (string.IsNullOrWhiteSpace(platformCode) || x.PlatformCode == platformCode)
&& (string.IsNullOrWhiteSpace(nickname) || x.StoreNickname.Contains(nickname))
&& (string.IsNullOrWhiteSpace(filter) || filter == "normal"

View File

@ -6,15 +6,23 @@ namespace Oms.Application.Services.Warehouse;
public partial class WarehouseService
{
private async Task<int> ResolveCustomerIdAsync(int? requestedCustomerId) =>
await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
private Task<int?> ResolveListCustomerIdAsync(int? requestedCustomerId) =>
WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
requestedCustomerId);
private async Task<CSku> GetSkuOrThrowAsync(int customerId, int skuId)
private Task<int> ResolveMutationCustomerIdAsync(int? requestedCustomerId) =>
WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
CustomerRepository,
CurrentUser,
requestedCustomerId);
private async Task<CSku> GetSkuOrThrowAsync(int? customerId, int skuId)
{
var entity = await SkuRepository.FirstOrDefaultAsync(x => x.Id == skuId && x.CustomerId == customerId);
var entity = customerId.HasValue
? await SkuRepository.FirstOrDefaultAsync(x => x.Id == skuId && x.CustomerId == customerId.Value)
: await SkuRepository.FirstOrDefaultAsync(x => x.Id == skuId);
if (entity == null)
{
throw new BusinessException("SKU 不存在");

View File

@ -19,13 +19,13 @@ public partial class WarehouseService
[HttpPost("/warehouse/inbound/list")]
public async Task<OmsPageResult<WarehouseInboundOutput>> GetInboundListAsync(WarehouseInboundListInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveListCustomerIdAsync(input.CustomerId);
var keyword = input.Keyword?.Trim();
var hasKeyword = !string.IsNullOrWhiteSpace(keyword);
var receiptStatus = input.ReceiptStatus?.Trim();
Expression<Func<CInboundNotice, bool>> predicate = x =>
x.CustomerId == customerId
(!customerId.HasValue || x.CustomerId == customerId.Value)
&& (!input.WarehouseId.HasValue || x.WarehouseId == input.WarehouseId.Value)
&& (string.IsNullOrWhiteSpace(receiptStatus) || x.ReceiptStatus == receiptStatus)
&& (!hasKeyword || x.NoticeNo.Contains(keyword!) || (x.MarkReference != null && x.MarkReference.Contains(keyword!)));
@ -66,7 +66,7 @@ public partial class WarehouseService
[FromQuery] int id,
[FromQuery] int? customerId = null)
{
var resolvedCustomerId = await ResolveCustomerIdAsync(customerId);
var resolvedCustomerId = await ResolveListCustomerIdAsync(customerId);
var notice = await GetInboundNoticeOrThrowAsync(resolvedCustomerId, id);
var boxes = await InboundBoxRepository.GetListAsync(x => x.InboundNoticeId == notice.Id);
boxes = boxes.OrderBy(x => x.BoxSeqNo).ThenBy(x => x.Id).ToList();
@ -103,7 +103,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/inbound/save")]
public async Task<WarehouseInboundDetailOutput> SaveInboundAsync(WarehouseInboundSaveInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveMutationCustomerIdAsync(input.CustomerId);
if (input.WarehouseId <= 0)
{
throw new BusinessException("仓库ID不能为空");
@ -194,7 +194,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/inbound/delete")]
public async Task DeleteInboundAsync(IdInput input)
{
var customerId = await ResolveCustomerIdAsync(null);
var customerId = await ResolveListCustomerIdAsync(null);
var notice = await GetInboundNoticeOrThrowAsync(customerId, input.Id);
if (notice.ReceiptStatus != WarehouseReceiptStatusCodes.Forecasted)
{
@ -212,7 +212,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/inbound/confirm-receive")]
public async Task ConfirmInboundReceiveAsync(WarehouseInboundConfirmReceiveInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveMutationCustomerIdAsync(input.CustomerId);
var notice = await GetInboundNoticeOrThrowAsync(customerId, input.InboundNoticeId);
if (notice.ReceiptStatus == WarehouseReceiptStatusCodes.Completed)
{
@ -299,9 +299,9 @@ public partial class WarehouseService
[HttpGet("/warehouse/inbound/summary")]
public async Task<WarehouseInboundSummaryOutput> GetInboundSummaryAsync([FromQuery] int? customerId = null, [FromQuery] int? warehouseId = null)
{
var resolvedCustomerId = await ResolveCustomerIdAsync(customerId);
var resolvedCustomerId = await ResolveListCustomerIdAsync(customerId);
var notices = await InboundNoticeRepository.GetListAsync(x =>
x.CustomerId == resolvedCustomerId
(!resolvedCustomerId.HasValue || x.CustomerId == resolvedCustomerId.Value)
&& (!warehouseId.HasValue || x.WarehouseId == warehouseId.Value));
return new WarehouseInboundSummaryOutput
@ -312,9 +312,11 @@ public partial class WarehouseService
};
}
private async Task<CInboundNotice> GetInboundNoticeOrThrowAsync(int customerId, int id)
private async Task<CInboundNotice> GetInboundNoticeOrThrowAsync(int? customerId, int id)
{
var entity = await InboundNoticeRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId);
var entity = customerId.HasValue
? await InboundNoticeRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId.Value)
: await InboundNoticeRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
{
throw new BusinessException("入库预报不存在");

View File

@ -16,16 +16,17 @@ public partial class WarehouseService
[HttpPost("/warehouse/inventory/list")]
public async Task<OmsPageResult<WarehouseInventoryOutput>> GetInventoryListAsync(WarehouseInventoryListInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveListCustomerIdAsync(input.CustomerId);
var inventories = await InventoryRepository.GetListAsync(x =>
x.CustomerId == customerId
(!customerId.HasValue || x.CustomerId == customerId.Value)
&& x.Qty > 0
&& (!input.WarehouseId.HasValue || x.WarehouseId == input.WarehouseId.Value));
var skuIds = inventories.Select(x => x.SkuId).Distinct().ToArray();
var skus = skuIds.Length == 0
? []
: await SkuRepository.GetListAsync(x => x.CustomerId == customerId && skuIds.Contains(x.Id));
: await SkuRepository.GetListAsync(x =>
(!customerId.HasValue || x.CustomerId == customerId.Value) && skuIds.Contains(x.Id));
var skuMap = skus.ToDictionary(x => x.Id);
var keyword = input.Keyword?.Trim();
@ -81,11 +82,11 @@ public partial class WarehouseService
throw new BusinessException("SKU 和仓库不能为空");
}
var resolvedCustomerId = await ResolveCustomerIdAsync(customerId);
var resolvedCustomerId = await ResolveListCustomerIdAsync(customerId);
await GetSkuOrThrowAsync(resolvedCustomerId, skuId);
var inventories = await InventoryRepository.GetListAsync(x =>
x.CustomerId == resolvedCustomerId
(!resolvedCustomerId.HasValue || x.CustomerId == resolvedCustomerId.Value)
&& x.WarehouseId == warehouseId
&& x.SkuId == skuId
&& x.Qty > 0);
@ -122,7 +123,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/inventory/relocate")]
public async Task RelocateInventoryAsync(WarehouseInventoryRelocateInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveMutationCustomerIdAsync(input.CustomerId);
if (input.SourceBinLocationId == input.TargetBinLocationId)
{
throw new BusinessException("源库位与目标库位不能相同");

View File

@ -19,13 +19,13 @@ public partial class WarehouseService
[HttpPost("/warehouse/parcel/list")]
public async Task<OmsPageResult<WarehouseParcelOutput>> GetParcelListAsync(WarehouseParcelListInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveListCustomerIdAsync(input.CustomerId);
var keyword = input.Keyword?.Trim();
var hasKeyword = !string.IsNullOrWhiteSpace(keyword);
var lifecycleStatus = input.LifecycleStatus?.Trim();
Expression<Func<CParcel, bool>> predicate = x =>
x.CustomerId == customerId
(!customerId.HasValue || x.CustomerId == customerId.Value)
&& (!input.WarehouseId.HasValue || x.WarehouseId == input.WarehouseId.Value)
&& (string.IsNullOrWhiteSpace(lifecycleStatus) || x.LifecycleStatus == lifecycleStatus)
&& (!hasKeyword || x.TrackingNo.Contains(keyword!) || (x.CarrierName != null && x.CarrierName.Contains(keyword!)));
@ -59,7 +59,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/parcel/save")]
public async Task<WarehouseParcelOutput> SaveParcelAsync(WarehouseParcelSaveInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveMutationCustomerIdAsync(input.CustomerId);
if (input.WarehouseId <= 0)
{
throw new BusinessException("仓库ID不能为空");
@ -141,7 +141,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/parcel/delete")]
public async Task DeleteParcelAsync(IdInput input)
{
var customerId = await ResolveCustomerIdAsync(null);
var customerId = await ResolveListCustomerIdAsync(null);
var parcel = await GetParcelOrThrowAsync(customerId, input.Id);
if (parcel.LifecycleStatus == WarehouseParcelLifecycleCodes.Stored)
{
@ -159,7 +159,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/parcel/putaway")]
public async Task PutawayParcelAsync(WarehouseParcelPutawayInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveMutationCustomerIdAsync(input.CustomerId);
var parcel = await GetParcelOrThrowAsync(customerId, input.ParcelId);
if (parcel.LifecycleStatus == WarehouseParcelLifecycleCodes.Stored)
{
@ -205,9 +205,11 @@ public partial class WarehouseService
await ParcelRepository.UpdateAsync(parcel);
}
private async Task<CParcel> GetParcelOrThrowAsync(int customerId, int id)
private async Task<CParcel> GetParcelOrThrowAsync(int? customerId, int id)
{
var entity = await ParcelRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId);
var entity = customerId.HasValue
? await ParcelRepository.FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId.Value)
: await ParcelRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
{
throw new BusinessException("包裹不存在");

View File

@ -17,12 +17,12 @@ public partial class WarehouseService
[HttpPost("/warehouse/sku/list")]
public async Task<OmsPageResult<WarehouseSkuOutput>> GetSkuListAsync(WarehouseSkuListInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveListCustomerIdAsync(input.CustomerId);
var keyword = input.Keyword?.Trim();
var hasKeyword = !string.IsNullOrWhiteSpace(keyword);
Expression<Func<Domain.WarehouseAggregate.Entities.CSku, bool>> predicate = x =>
x.CustomerId == customerId
(!customerId.HasValue || x.CustomerId == customerId.Value)
&& (!hasKeyword || x.SkuCode.Contains(keyword!) || x.SkuName.Contains(keyword!));
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
@ -37,7 +37,8 @@ public partial class WarehouseService
var skuIds = entities.Select(x => x.Id).ToArray();
var inventories = skuIds.Length == 0
? []
: await InventoryRepository.GetListAsync(x => x.CustomerId == customerId && skuIds.Contains(x.SkuId));
: await InventoryRepository.GetListAsync(x =>
(!customerId.HasValue || x.CustomerId == customerId.Value) && skuIds.Contains(x.SkuId));
var qtyMap = inventories
.GroupBy(x => x.SkuId)
.ToDictionary(g => g.Key, g => g.Sum(x => x.Qty));
@ -58,9 +59,11 @@ public partial class WarehouseService
[HttpGet("/warehouse/sku/detail")]
public async Task<WarehouseSkuOutput> GetSkuDetailAsync([FromQuery] int id, [FromQuery] int? customerId = null)
{
var resolvedCustomerId = await ResolveCustomerIdAsync(customerId);
var resolvedCustomerId = await ResolveListCustomerIdAsync(customerId);
var entity = await GetSkuOrThrowAsync(resolvedCustomerId, id);
var inventories = await InventoryRepository.GetListAsync(x => x.CustomerId == resolvedCustomerId && x.SkuId == id);
var inventories = await InventoryRepository.GetListAsync(x =>
(!resolvedCustomerId.HasValue || x.CustomerId == resolvedCustomerId.Value)
&& x.SkuId == id);
return MapSkuOutput(entity, inventories.Sum(x => x.Qty));
}
@ -72,7 +75,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/sku/save")]
public async Task<WarehouseSkuOutput> SaveSkuAsync(WarehouseSkuSaveInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveMutationCustomerIdAsync(input.CustomerId);
var skuCode = input.SkuCode.Trim();
var skuName = input.SkuName.Trim();
if (string.IsNullOrWhiteSpace(skuCode) || string.IsNullOrWhiteSpace(skuName))
@ -125,10 +128,10 @@ public partial class WarehouseService
[HttpPost("/warehouse/sku/delete")]
public async Task DeleteSkuAsync(IdInput input)
{
var customerId = await ResolveCustomerIdAsync(null);
var customerId = await ResolveListCustomerIdAsync(null);
var entity = await GetSkuOrThrowAsync(customerId, input.Id);
var hasInventory = await InventoryRepository.CountAsync(x =>
x.CustomerId == customerId && x.SkuId == entity.Id && x.Qty > 0);
x.SkuId == entity.Id && x.Qty > 0);
if (hasInventory > 0)
{
throw new BusinessException("SKU 仍有库存,不能删除");
@ -145,7 +148,7 @@ public partial class WarehouseService
[HttpPost("/warehouse/sku/bind-mapping")]
public async Task<WarehouseSkuMappingOutput> BindSkuMappingAsync(WarehouseSkuBindMappingInput input)
{
var customerId = await ResolveCustomerIdAsync(input.CustomerId);
var customerId = await ResolveMutationCustomerIdAsync(input.CustomerId);
var platformSku = input.PlatformSku.Trim();
if (string.IsNullOrWhiteSpace(platformSku))
{

View File

@ -9,15 +9,24 @@ namespace Oms.Application.Shared;
/// </summary>
public static class WarehouseCustomerHelper
{
/// <summary>
/// 列表/汇总查询用的客户 ID:客户登录强制为自身;管理员未传 customerId 时返回 null(查询全部)。
/// </summary>
public static Task<int?> ResolveListCustomerIdAsync(
ICustomerRepository customerRepository,
ICurrentUser currentUser,
int? requestedCustomerId = null) =>
OmsSessionHelper.ResolveListCustomerIdAsync(customerRepository, currentUser, requestedCustomerId);
/// <summary>
/// 写入/删除等必须明确客户归属的操作:客户登录强制为自身;管理员须传 customerId。
/// </summary>
public static async Task<int> ResolveRequiredCustomerIdAsync(
ICustomerRepository customerRepository,
ICurrentUser currentUser,
int? requestedCustomerId = null)
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(
customerRepository,
currentUser,
requestedCustomerId);
var customerId = await ResolveListCustomerIdAsync(customerRepository, currentUser, requestedCustomerId);
if (!customerId.HasValue)
{
throw new BusinessException("客户ID不能为空");