diff --git a/.gitignore b/.gitignore
index 02f9e1c..e72706e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,8 +9,13 @@ riderModule.iml
.idea/
/.vs
/Fake.sln.DotSettings.user
+*.DotSettings.user
+SimpleAdmin.sln.DotSettings.user
Logs/
+*.log
+api-*.log
+build-warnings.txt
node_modules/
diff --git a/SimpleAdmin.sln.DotSettings.user b/SimpleAdmin.sln.DotSettings.user
deleted file mode 100644
index 39396e3..0000000
--- a/SimpleAdmin.sln.DotSettings.user
+++ /dev/null
@@ -1,25 +0,0 @@
-
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- ForceIncluded
- <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from <src>\<SimpleAdmin.Api.IntegrationTests>" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
- <Project Location="D:\my\itfx\admin\src\SimpleAdmin.Api.IntegrationTests" Presentation="<src>\<SimpleAdmin.Api.IntegrationTests>" />
-</SessionState>
\ No newline at end of file
diff --git a/sql/fix_concurrency_stamp_missing.sql b/sql/fix_concurrency_stamp_missing.sql
new file mode 100644
index 0000000..6658e5a
--- /dev/null
+++ b/sql/fix_concurrency_stamp_missing.sql
@@ -0,0 +1,63 @@
+-- 给缺少 ConcurrencyStamp 的 OMS 表补列(可重复执行)
+-- Fake AggregateRoot 自带该字段,SqlSugar 查询会带上;库表没有就会报:
+-- Unknown column 'ConcurrencyStamp' in 'field list'
+--
+-- 注意:不要用 DEFAULT (UUID())。在 STATEMENT/MIXED 复制下会触发:
+-- 1674 Statement is unsafe because it uses a system function that may return a different value on the replica.
+-- 默认用固定 GUID;插入/更新时由 ORM 写入真实 UUID。
+--
+-- 用法:在业务库执行本脚本;若仍报错,把报错 SQL 里的表名追加到下方列表。
+
+SET @tables := 't_order_stock_bind,C_inventory,C_parcel,C_parcel_item,C_parcel_arrival,C_sku,C_bin_location,C_inbound_notice,C_inbound_box,C_inbound_box_line,C_sku_platform_map,t_sales_store,t_sales_store_order,t_sales_store_order_line,t_customer_sender_address';
+
+DROP PROCEDURE IF EXISTS sp_add_concurrency_stamp_if_missing;
+DELIMITER $$
+CREATE PROCEDURE sp_add_concurrency_stamp_if_missing()
+BEGIN
+ DECLARE done INT DEFAULT 0;
+ DECLARE tname VARCHAR(128);
+ DECLARE cur CURSOR FOR
+ SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(@tables, ',', n.n), ',', -1)) AS t
+ FROM (
+ SELECT a.N + b.N * 10 + 1 AS n
+ FROM
+ (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a,
+ (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b
+ ) n
+ WHERE n.n <= 1 + (LENGTH(@tables) - LENGTH(REPLACE(@tables, ',', '')));
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
+
+ OPEN cur;
+ read_loop: LOOP
+ FETCH cur INTO tname;
+ IF done THEN
+ LEAVE read_loop;
+ END IF;
+ IF tname IS NULL OR tname = '' THEN
+ ITERATE read_loop;
+ END IF;
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = tname
+ ) THEN
+ ITERATE read_loop;
+ END IF;
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = tname AND COLUMN_NAME = 'ConcurrencyStamp'
+ ) THEN
+ SET @ddl := CONCAT(
+ 'ALTER TABLE `', tname,
+ '` ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT ''00000000-0000-0000-0000-000000000000'' COMMENT ''并发戳'''
+ );
+ PREPARE stmt FROM @ddl;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+ END LOOP;
+ CLOSE cur;
+END$$
+DELIMITER ;
+
+CALL sp_add_concurrency_stamp_if_missing();
+DROP PROCEDURE IF EXISTS sp_add_concurrency_stamp_if_missing;
diff --git a/sql/migrate_t_order_stock_bind.sql b/sql/migrate_t_order_stock_bind.sql
index 4b5afd8..3df34ca 100644
--- a/sql/migrate_t_order_stock_bind.sql
+++ b/sql/migrate_t_order_stock_bind.sql
@@ -1,5 +1,6 @@
-- 物流单绑定包裹/库存:t_order_stock_bind + C_inventory/C_parcel_item 冻结与可用字段
--- 见 oms系统设计-050801.md §4.2.11 / §4.4.6
+-- 见 oms系统设计-050801.md §4.2.11 / §4.4.6 / §3.1.2
+-- ConcurrencyStamp 默认用固定 GUID,避免 DEFAULT (UUID()) 触发复制 1674
-- 可重复执行
CREATE TABLE IF NOT EXISTS `t_order_stock_bind` (
@@ -23,6 +24,7 @@ CREATE TABLE IF NOT EXISTS `t_order_stock_bind` (
`AttributeText` VARCHAR(256) NULL,
`Remark` VARCHAR(512) NULL,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
+ `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
`CreateUserId` INT NOT NULL,
`CreateTime` DATETIME NOT NULL,
`UpdateUserId` INT NULL,
@@ -33,6 +35,18 @@ CREATE TABLE IF NOT EXISTS `t_order_stock_bind` (
KEY `idx_osb_sku` (`CustomerId`, `WarehouseId`, `SkuId`, `Status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物流单仓储绑定明细';
+-- 已建表但缺 ConcurrencyStamp 时补列(可重复执行)
+SET @col_exists := (
+ SELECT COUNT(1) FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order_stock_bind' AND COLUMN_NAME = 'ConcurrencyStamp'
+);
+SET @sql := IF(
+ @col_exists = 0,
+ 'ALTER TABLE `t_order_stock_bind` ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT ''00000000-0000-0000-0000-000000000000'' COMMENT ''并发戳'' AFTER `IsDeleted`',
+ 'SELECT ''t_order_stock_bind.ConcurrencyStamp already exists'' AS info'
+);
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
-- C_inventory.FrozenQty
SET @col_exists := (
SELECT COUNT(1) FROM information_schema.COLUMNS
diff --git a/src/Oms.Application/Dtos/Orders/OrderOutput.cs b/src/Oms.Application/Dtos/Orders/OrderOutput.cs
index 6e375d6..2ac4836 100644
--- a/src/Oms.Application/Dtos/Orders/OrderOutput.cs
+++ b/src/Oms.Application/Dtos/Orders/OrderOutput.cs
@@ -95,6 +95,16 @@ public class OrderOutput
///
public int? CustomerId { get; set; }
+ ///
+ /// 客户名称。
+ ///
+ public string? CustomerName { get; set; }
+
+ ///
+ /// 客户编码。
+ ///
+ public string? CustomerCode { get; set; }
+
///
/// 订单来源。
///
diff --git a/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs b/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs
index 16a0f34..2cc2f38 100644
--- a/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs
+++ b/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs
@@ -24,6 +24,10 @@ public class PlatformStoreOutput
public int CustomerId { get; set; }
+ public string? CustomerName { get; set; }
+
+ public string? CustomerCode { get; set; }
+
public string PlatformCode { get; set; } = string.Empty;
public string PlatformName { get; set; } = string.Empty;
@@ -186,6 +190,10 @@ public class PlatformStoreOrderOutput
public int CustomerId { get; set; }
+ public string? CustomerName { get; set; }
+
+ public string? CustomerCode { get; set; }
+
public int StoreId { get; set; }
public string StoreNickname { get; set; } = string.Empty;
diff --git a/src/Oms.Application/Dtos/Warehouse/WarehouseDtos.cs b/src/Oms.Application/Dtos/Warehouse/WarehouseDtos.cs
index f858314..5aa9e78 100644
--- a/src/Oms.Application/Dtos/Warehouse/WarehouseDtos.cs
+++ b/src/Oms.Application/Dtos/Warehouse/WarehouseDtos.cs
@@ -373,6 +373,10 @@ public class WarehouseParcelOutput
public int CustomerId { get; set; }
+ public string? CustomerName { get; set; }
+
+ public string? CustomerCode { get; set; }
+
public int WarehouseId { get; set; }
public string TrackingNo { get; set; } = string.Empty;
@@ -441,6 +445,12 @@ public class WarehouseInventoryListInput : WarehousePageInput
public class WarehouseInventoryOutput
{
+ public int CustomerId { get; set; }
+
+ public string? CustomerName { get; set; }
+
+ public string? CustomerCode { get; set; }
+
public int SkuId { get; set; }
public string SkuCode { get; set; } = string.Empty;
diff --git a/src/Oms.Application/Services/Orders/OrderService.Helpers.cs b/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
index bf023c5..cf1e869 100644
--- a/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
@@ -79,6 +79,16 @@ public partial class OrderService
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
orders.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
+ var customerIds = orders
+ .Where(x => x.CustomerId is > 0)
+ .Select(x => x.CustomerId!.Value)
+ .Distinct()
+ .ToArray();
+ var customers = customerIds.Length == 0
+ ? []
+ : await CustomerRepository.GetListAsync(x => customerIds.Contains(x.Id));
+ var customerMap = customers.ToDictionary(x => x.Id);
+
return orders.Select(order =>
{
senderMap.TryGetValue(order.Id, out var sender);
@@ -91,6 +101,14 @@ public partial class OrderService
var receivableAmount = feeOutputs
.Where(x => x.Type == OrderFeeTypeCodes.Receivable)
.Sum(x => x.Amount);
+ string? customerName = null;
+ string? customerCode = null;
+ if (order.CustomerId is > 0 && customerMap.TryGetValue(order.CustomerId.Value, out var customer))
+ {
+ customerName = customer.CustomerName;
+ customerCode = customer.CustomerCode;
+ }
+
return new OrderOutput
{
Id = order.Id,
@@ -119,6 +137,8 @@ public partial class OrderService
? warehouse.WarehouseName
: null,
CustomerId = order.CustomerId,
+ CustomerName = customerName,
+ CustomerCode = customerCode,
OrderSource = string.IsNullOrWhiteSpace(order.OrderSource)
? OrderSourceCodes.Manual
: order.OrderSource,
diff --git a/src/Oms.Application/Services/Orders/OrderService.StockBind.cs b/src/Oms.Application/Services/Orders/OrderService.StockBind.cs
index d4bbf01..f67978f 100644
--- a/src/Oms.Application/Services/Orders/OrderService.StockBind.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.StockBind.cs
@@ -52,12 +52,12 @@ public partial class OrderService
var order = await GetOrderOrThrowAsync(input.OrderId);
EnsureOrderCanBindStock(order);
var warehouseId = ResolveBindWarehouseId(order, input.WarehouseId);
- var customerId = RequireOrderCustomerId(order);
+ var customerId = await ResolveStockBindCustomerIdAsync(order);
var inventories = await StockBindInventoryRepository.GetListAsync(x =>
x.CustomerId == customerId
&& x.WarehouseId == warehouseId
- && x.AvailableQty > 0);
+ && (x.AvailableQty > 0 || x.Qty > x.FrozenQty));
var skuIds = inventories.Select(x => x.SkuId).Distinct().ToArray();
var skus = skuIds.Length == 0
@@ -111,7 +111,7 @@ public partial class OrderService
var order = await GetOrderOrThrowAsync(input.OrderId);
EnsureOrderCanBindStock(order);
var warehouseId = ResolveBindWarehouseId(order, input.WarehouseId);
- var customerId = RequireOrderCustomerId(order);
+ var customerId = await ResolveStockBindCustomerIdAsync(order);
var lifecycle = input.LifecycleStatus?.Trim();
var filterLifecycle = !string.IsNullOrWhiteSpace(lifecycle)
@@ -194,7 +194,7 @@ public partial class OrderService
var order = await GetOrderOrThrowAsync(input.OrderId);
EnsureOrderCanBindStock(order);
await EnsureNoDeductedBindsAsync(order.Id);
- var customerId = RequireOrderCustomerId(order);
+ var customerId = await ResolveStockBindCustomerIdAsync(order);
var warehouseId = ResolveBindWarehouseId(order, null);
var items = input.Items ?? [];
@@ -500,7 +500,7 @@ public partial class OrderService
x.CustomerId == customerId
&& x.WarehouseId == warehouseId
&& x.SkuId == skuId
- && x.AvailableQty > 0);
+ && (x.AvailableQty > 0 || x.Qty > x.FrozenQty));
rows = rows.OrderBy(x => x.BinLocationId).ToList();
}
@@ -641,6 +641,23 @@ public partial class OrderService
return order.CustomerId.Value;
}
+ ///
+ /// 绑定客户上下文:客户登录与仓储模块一致(会话客户);管理端按订单客户。
+ ///
+ private async Task ResolveStockBindCustomerIdAsync(Order order)
+ {
+ var sessionCustomerId = await OmsSessionHelper.ResolveListCustomerIdAsync(
+ CustomerRepository,
+ CurrentUser,
+ null);
+ if (sessionCustomerId is > 0)
+ {
+ return sessionCustomerId.Value;
+ }
+
+ return RequireOrderCustomerId(order);
+ }
+
private static int ResolveBindWarehouseId(Order order, int? requestedWarehouseId)
{
if (requestedWarehouseId is > 0)
diff --git a/src/Oms.Application/Services/Orders/OrderService.cs b/src/Oms.Application/Services/Orders/OrderService.cs
index 9b98ca5..f13ac6a 100644
--- a/src/Oms.Application/Services/Orders/OrderService.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.cs
@@ -483,10 +483,19 @@ public partial class OrderService : ApplicationService
return;
}
- if (order.CustomerId != customerId.Value)
+ if (order.CustomerId == customerId.Value)
{
- throw new BusinessException("订单不存在");
+ return;
}
+
+ // 兼容历史脏数据:下单人是当前客户账号,但订单 CustomerId 未写对
+ var mapId = OmsSessionHelper.TryGetCustomerMapId(CurrentUser);
+ if (mapId is > 0 && order.CreateUserId == mapId.Value)
+ {
+ return;
+ }
+
+ throw new BusinessException("订单不存在");
}
private async Task GetOrderOrThrowAsync(int id)
diff --git a/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs b/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs
index ae2df79..45f11ee 100644
--- a/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs
+++ b/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs
@@ -71,6 +71,12 @@ public class PlatformStoreOrderService : ApplicationService
: await OrderRepository.GetListAsync(x => linkedOrderIds.Contains(x.Id));
var linkedOrderMap = linkedOrders.ToDictionary(x => x.Id);
+ var customerIds = entities.Select(x => x.CustomerId).Distinct().ToArray();
+ var customers = customerIds.Length == 0
+ ? []
+ : await CustomerRepository.GetListAsync(x => customerIds.Contains(x.Id));
+ var customerMap = customers.ToDictionary(x => x.Id);
+
return new OmsPageResult
{
Items = entities.Select(x =>
@@ -82,7 +88,14 @@ public class PlatformStoreOrderService : ApplicationService
linkedServiceNo = linkedOrder.ServiceNo;
}
- return MapOrderOutput(x, store?.StoreNickname ?? string.Empty, [], linkedServiceNo: linkedServiceNo);
+ customerMap.TryGetValue(x.CustomerId, out var customer);
+ return MapOrderOutput(
+ x,
+ store?.StoreNickname ?? string.Empty,
+ [],
+ linkedServiceNo: linkedServiceNo,
+ customerName: customer?.CustomerName,
+ customerCode: customer?.CustomerCode);
}).ToList(),
Total = total
};
@@ -110,8 +123,16 @@ public class PlatformStoreOrderService : ApplicationService
: await SkuRepository.GetListAsync(x => skuIds.Contains(x.Id));
var skuMap = skus.ToDictionary(x => x.Id);
var linkedServiceNo = await ResolveLinkedServiceNoAsync(order.LinkedOrderId);
+ var customer = await CustomerRepository.FirstOrDefaultAsync(x => x.Id == order.CustomerId);
- return MapOrderOutput(order, store?.StoreNickname ?? string.Empty, lines, skuMap, linkedServiceNo);
+ return MapOrderOutput(
+ order,
+ store?.StoreNickname ?? string.Empty,
+ lines,
+ skuMap,
+ linkedServiceNo,
+ customer?.CustomerName,
+ customer?.CustomerCode);
}
///
@@ -692,11 +713,15 @@ public class PlatformStoreOrderService : ApplicationService
string storeNickname,
IReadOnlyCollection lines,
IReadOnlyDictionary? skuMap = null,
- string? linkedServiceNo = null) =>
+ string? linkedServiceNo = null,
+ string? customerName = null,
+ string? customerCode = null) =>
new()
{
Id = order.Id,
CustomerId = order.CustomerId,
+ CustomerName = customerName,
+ CustomerCode = customerCode,
StoreId = order.StoreId,
StoreNickname = storeNickname,
PlatformCode = order.PlatformCode,
diff --git a/src/Oms.Application/Services/Orders/PlatformStoreService.cs b/src/Oms.Application/Services/Orders/PlatformStoreService.cs
index 3244f7e..c7ce7c4 100644
--- a/src/Oms.Application/Services/Orders/PlatformStoreService.cs
+++ b/src/Oms.Application/Services/Orders/PlatformStoreService.cs
@@ -43,9 +43,15 @@ public class PlatformStoreService : ApplicationService
new Dictionary { [nameof(SalesStore.UpdateTime)] = false, [nameof(SalesStore.Id)] = false });
var total = await StoreRepository.CountAsync(predicate);
+ var customerIds = entities.Select(x => x.CustomerId).Distinct().ToArray();
+ var customers = customerIds.Length == 0
+ ? []
+ : await CustomerRepository.GetListAsync(x => customerIds.Contains(x.Id));
+ var customerMap = customers.ToDictionary(x => x.Id);
+
return new OmsPageResult
{
- Items = entities.Select(MapOutput).ToList(),
+ Items = entities.Select(x => MapOutput(x, customerMap)).ToList(),
Total = total
};
}
@@ -445,11 +451,24 @@ public class PlatformStoreService : ApplicationService
};
}
- private static PlatformStoreOutput MapOutput(SalesStore entity) =>
- new()
+ private static PlatformStoreOutput MapOutput(
+ SalesStore entity,
+ IReadOnlyDictionary? customerMap = null)
+ {
+ string? customerName = null;
+ string? customerCode = null;
+ if (customerMap != null && customerMap.TryGetValue(entity.CustomerId, out var customer))
+ {
+ customerName = customer.CustomerName;
+ customerCode = customer.CustomerCode;
+ }
+
+ return new PlatformStoreOutput
{
Id = entity.Id,
CustomerId = entity.CustomerId,
+ CustomerName = customerName,
+ CustomerCode = customerCode,
PlatformCode = entity.PlatformCode,
PlatformName = ResolvePlatformName(entity.PlatformCode),
StoreNickname = entity.StoreNickname,
@@ -462,6 +481,7 @@ public class PlatformStoreService : ApplicationService
Remark = entity.Remark,
CreateTime = entity.CreateTime
};
+ }
private static string ResolvePlatformName(string platformCode) => platformCode.ToLowerInvariant() switch
{
diff --git a/src/Oms.Application/Services/Warehouse/WarehouseService.Inventory.cs b/src/Oms.Application/Services/Warehouse/WarehouseService.Inventory.cs
index 152bd54..e40e552 100644
--- a/src/Oms.Application/Services/Warehouse/WarehouseService.Inventory.cs
+++ b/src/Oms.Application/Services/Warehouse/WarehouseService.Inventory.cs
@@ -32,14 +32,24 @@ public partial class WarehouseService
(!hasCustomerFilter || x.CustomerId == customerIdValue) && skuIds.Contains(x.Id));
var skuMap = skus.ToDictionary(x => x.Id);
+ var customerIds = inventories.Select(x => x.CustomerId).Distinct().ToArray();
+ var customers = customerIds.Length == 0
+ ? []
+ : await CustomerRepository.GetListAsync(x => customerIds.Contains(x.Id));
+ var customerMap = customers.ToDictionary(x => x.Id);
+
var keyword = input.Keyword?.Trim();
var grouped = inventories
- .GroupBy(x => new { x.SkuId, x.WarehouseId })
+ .GroupBy(x => new { x.CustomerId, x.SkuId, x.WarehouseId })
.Select(g =>
{
skuMap.TryGetValue(g.Key.SkuId, out var sku);
+ customerMap.TryGetValue(g.Key.CustomerId, out var customer);
return new WarehouseInventoryOutput
{
+ CustomerId = g.Key.CustomerId,
+ CustomerName = customer?.CustomerName,
+ CustomerCode = customer?.CustomerCode,
SkuId = g.Key.SkuId,
SkuCode = sku?.SkuCode ?? string.Empty,
SkuName = sku?.SkuName ?? string.Empty,
@@ -53,8 +63,11 @@ public partial class WarehouseService
.Where(x =>
string.IsNullOrWhiteSpace(keyword)
|| x.SkuCode.Contains(keyword!, StringComparison.OrdinalIgnoreCase)
- || x.SkuName.Contains(keyword!, StringComparison.OrdinalIgnoreCase))
- .OrderBy(x => x.SkuCode)
+ || x.SkuName.Contains(keyword!, StringComparison.OrdinalIgnoreCase)
+ || (x.CustomerName?.Contains(keyword!, StringComparison.OrdinalIgnoreCase) ?? false)
+ || (x.CustomerCode?.Contains(keyword!, StringComparison.OrdinalIgnoreCase) ?? false))
+ .OrderBy(x => x.CustomerCode)
+ .ThenBy(x => x.SkuCode)
.ThenBy(x => x.WarehouseId)
.ToList();
diff --git a/src/Oms.Application/Services/Warehouse/WarehouseService.Parcel.cs b/src/Oms.Application/Services/Warehouse/WarehouseService.Parcel.cs
index fc1a776..53b1641 100644
--- a/src/Oms.Application/Services/Warehouse/WarehouseService.Parcel.cs
+++ b/src/Oms.Application/Services/Warehouse/WarehouseService.Parcel.cs
@@ -55,9 +55,25 @@ public partial class WarehouseService
? []
: await ParcelItemRepository.GetListAsync(x => parcelIds.Contains(x.ParcelId));
+ var customerIds = entities.Select(x => x.CustomerId).Distinct().ToArray();
+ var customers = customerIds.Length == 0
+ ? []
+ : await CustomerRepository.GetListAsync(x => customerIds.Contains(x.Id));
+ var customerMap = customers.ToDictionary(x => x.Id);
+
return new OmsPageResult
{
- Items = entities.Select(x => MapParcelOutput(x, items.Where(i => i.ParcelId == x.Id))).ToList(),
+ Items = entities.Select(x =>
+ {
+ var output = MapParcelOutput(x, items.Where(i => i.ParcelId == x.Id));
+ if (customerMap.TryGetValue(x.CustomerId, out var customer))
+ {
+ output.CustomerName = customer.CustomerName;
+ output.CustomerCode = customer.CustomerCode;
+ }
+
+ return output;
+ }).ToList(),
Total = total
};
}
diff --git a/src/Oms.Application/Shared/OmsSessionHelper.cs b/src/Oms.Application/Shared/OmsSessionHelper.cs
index aaf8ba8..3b603fd 100644
--- a/src/Oms.Application/Shared/OmsSessionHelper.cs
+++ b/src/Oms.Application/Shared/OmsSessionHelper.cs
@@ -1,3 +1,4 @@
+using System.Security.Claims;
using Fake.Application;
using Fake.Users;
using Oms.Domain.CustomersAggregate.Entities;
@@ -15,16 +16,32 @@ public static class OmsSessionHelper
///
public const string LoginTypeClaim = "loginType";
+ ///
+ /// JWT 中 RBAC mapId Claim 名称(与 FakeClaimTypes.UserId 对齐)。
+ ///
+ public const string MapIdClaim = "mapId";
+
private const string CustomerLoginType = "1";
+ private const string CustomerRoleName = "Customer";
///
/// 当前会话是否为客户门户登录。
///
- public static bool IsCustomerLogin(ICurrentUser currentUser) =>
- string.Equals(
- currentUser.FindClaimOrNull(LoginTypeClaim)?.Value,
- CustomerLoginType,
- StringComparison.Ordinal);
+ public static bool IsCustomerLogin(ICurrentUser currentUser)
+ {
+ if (string.Equals(
+ currentUser.FindClaimOrNull(LoginTypeClaim)?.Value,
+ CustomerLoginType,
+ StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ // 兼容 loginType 丢失但 role=Customer 仍在的令牌
+ var role = currentUser.FindClaimOrNull(ClaimTypes.Role)?.Value
+ ?? currentUser.FindClaimOrNull("role")?.Value;
+ return string.Equals(role, CustomerRoleName, StringComparison.OrdinalIgnoreCase);
+ }
///
/// 客户登录时返回 mapId(对应 t_customer.UserId / 订单 CreateUserId);管理员返回 null。
@@ -37,7 +54,19 @@ public static class OmsSessionHelper
}
var userId = currentUser.GetId();
- return userId > 0 ? userId : null;
+ if (userId > 0)
+ {
+ return userId;
+ }
+
+ // GetId 未绑到 mapId 时,直接读 claim,避免客户会话被当成管理员(不过滤)
+ var mapIdRaw = currentUser.FindClaimOrNull(MapIdClaim)?.Value;
+ if (int.TryParse(mapIdRaw, out var mapId) && mapId > 0)
+ {
+ return mapId;
+ }
+
+ return null;
}
///