From 010c2b7043a6be8597c50be011e7c786e7e00b3d Mon Sep 17 00:00:00 2001
From: MSuMshk <2039814060@qq.com>
Date: Thu, 29 Jan 2026 14:04:20 +0000
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=95=86=E5=93=81=E6=A8=A1=E5=9D=97?=
=?UTF-8?q?=E7=A7=BB=E9=99=A4=E7=A7=9F=E6=88=B7=E4=B8=8A=E4=B8=8B=E6=96=87?=
=?UTF-8?q?=E4=BE=9D=E8=B5=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Handlers/CreateProductCommandHandler.cs | 24 +++++++++++---
.../Handlers/DeleteProductCommandHandler.cs | 12 +++----
.../Handlers/GetStoreMenuQueryHandler.cs | 15 ++++++---
.../Handlers/PublishProductCommandHandler.cs | 12 +++----
.../ReplaceProductAddonsCommandHandler.cs | 14 ++++-----
.../ReplaceProductAttributesCommandHandler.cs | 14 ++++-----
.../ReplaceProductMediaCommandHandler.cs | 11 +++----
...eplaceProductPricingRulesCommandHandler.cs | 11 +++----
.../ReplaceProductSkusCommandHandler.cs | 13 ++++----
.../UnpublishProductCommandHandler.cs | 9 ++----
.../Handlers/UpdateProductCommandHandler.cs | 31 +++++++++++++------
11 files changed, 95 insertions(+), 71 deletions(-)
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/CreateProductCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/CreateProductCommandHandler.cs
index 2bf1e33..96be047 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/CreateProductCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/CreateProductCommandHandler.cs
@@ -4,24 +4,40 @@ using TakeoutSaaS.Application.App.Products.Commands;
using TakeoutSaaS.Application.App.Products.Dto;
using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
+using TakeoutSaaS.Domain.Stores.Repositories;
+using TakeoutSaaS.Shared.Abstractions.Constants;
+using TakeoutSaaS.Shared.Abstractions.Exceptions;
namespace TakeoutSaaS.Application.App.Products.Handlers;
///
/// 创建商品命令处理器。
///
-public sealed class CreateProductCommandHandler(IProductRepository productRepository, ILogger logger)
+public sealed class CreateProductCommandHandler(
+ IProductRepository productRepository,
+ IStoreRepository storeRepository,
+ ILogger logger)
: IRequestHandler
{
private readonly IProductRepository _productRepository = productRepository;
+ private readonly IStoreRepository _storeRepository = storeRepository;
private readonly ILogger _logger = logger;
///
public async Task Handle(CreateProductCommand request, CancellationToken cancellationToken)
{
- // 1. 构建实体
+ // 1. 校验门店存在并解析租户
+ var store = await _storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
+ if (store is null)
+ {
+ throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
+ }
+ var tenantId = store.TenantId;
+
+ // 2. (空行后) 构建实体并写入租户
var product = new Product
{
+ TenantId = tenantId,
StoreId = request.StoreId,
CategoryId = request.CategoryId,
SpuCode = request.SpuCode.Trim(),
@@ -42,12 +58,12 @@ public sealed class CreateProductCommandHandler(IProductRepository productReposi
IsFeatured = request.IsFeatured
};
- // 2. 持久化
+ // 3. (空行后) 持久化
await _productRepository.AddProductAsync(product, cancellationToken);
await _productRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("创建商品 {ProductId} - {ProductName}", product.Id, product.Name);
- // 3. 返回 DTO
+ // 4. (空行后) 返回 DTO
return MapToDto(product);
}
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/DeleteProductCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/DeleteProductCommandHandler.cs
index f06cfa1..8c11f07 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/DeleteProductCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/DeleteProductCommandHandler.cs
@@ -2,7 +2,6 @@ using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Products.Commands;
using TakeoutSaaS.Domain.Products.Repositories;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -11,27 +10,24 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class DeleteProductCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler
{
private readonly IProductRepository _productRepository = productRepository;
- private readonly ITenantProvider _tenantProvider = tenantProvider;
private readonly ILogger _logger = logger;
///
public async Task Handle(DeleteProductCommand request, CancellationToken cancellationToken)
{
- // 1. 校验存在性
- var tenantId = _tenantProvider.GetCurrentTenantId();
- var existing = await _productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 校验存在性(跨租户)
+ var existing = await _productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (existing == null)
{
return false;
}
- // 2. 删除
- await _productRepository.DeleteProductAsync(request.ProductId, tenantId, cancellationToken);
+ // 2. (空行后) 删除
+ await _productRepository.DeleteProductAsync(request.ProductId, existing.TenantId, cancellationToken);
await _productRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("删除商品 {ProductId}", request.ProductId);
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/GetStoreMenuQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/GetStoreMenuQueryHandler.cs
index bde1465..65154a0 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/GetStoreMenuQueryHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/GetStoreMenuQueryHandler.cs
@@ -9,7 +9,9 @@ using TakeoutSaaS.Application.App.Products.Queries;
using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Enums;
using TakeoutSaaS.Domain.Products.Repositories;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
+using TakeoutSaaS.Domain.Stores.Repositories;
+using TakeoutSaaS.Shared.Abstractions.Constants;
+using TakeoutSaaS.Shared.Abstractions.Exceptions;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -18,15 +20,20 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class GetStoreMenuQueryHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
+ IStoreRepository storeRepository,
ILogger logger)
: IRequestHandler
{
///
public async Task Handle(GetStoreMenuQuery request, CancellationToken cancellationToken)
{
- // 1. 准备上下文
- var tenantId = tenantProvider.GetCurrentTenantId();
+ // 1. 校验门店存在并解析租户
+ var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
+ if (store is null)
+ {
+ throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
+ }
+ var tenantId = store.TenantId;
var updatedAfterUtc = request.UpdatedAfter?.ToUniversalTime();
// 2. 获取分类
var categories = await productRepository.GetCategoriesByStoreAsync(tenantId, request.StoreId, true, cancellationToken);
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/PublishProductCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/PublishProductCommandHandler.cs
index fd71ada..4744c3e 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/PublishProductCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/PublishProductCommandHandler.cs
@@ -7,7 +7,6 @@ using TakeoutSaaS.Domain.Products.Enums;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -16,29 +15,28 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class PublishProductCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler
{
///
public async Task Handle(PublishProductCommand request, CancellationToken cancellationToken)
{
- // 1. 读取商品
- var tenantId = tenantProvider.GetCurrentTenantId();
- var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 读取商品(跨租户)
+ var product = await productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (product is null)
{
return null;
}
+ var tenantId = product.TenantId;
- // 2. 校验 SKU 可售
+ // 2. (空行后) 校验 SKU 可售
var skus = await productRepository.GetSkusAsync(product.Id, tenantId, cancellationToken);
if (skus.Count == 0)
{
throw new BusinessException(ErrorCodes.Conflict, "请先配置可售 SKU 后再上架");
}
- // 3. 上架
+ // 3. (空行后) 上架
product.Status = ProductStatus.OnSale;
await productRepository.UpdateProductAsync(product, cancellationToken);
await productRepository.SaveChangesAsync(cancellationToken);
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAddonsCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAddonsCommandHandler.cs
index af61144..d214a99 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAddonsCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAddonsCommandHandler.cs
@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -15,33 +14,33 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class ReplaceProductAddonsCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler>
{
///
public async Task> Handle(ReplaceProductAddonsCommand request, CancellationToken cancellationToken)
{
- // 1. 校验商品
- var tenantId = tenantProvider.GetCurrentTenantId();
- var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 校验商品(跨租户)
+ var product = await productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (product is null)
{
throw new BusinessException(ErrorCodes.NotFound, "商品不存在");
}
+ var tenantId = product.TenantId;
- // 2. 校验组名唯一
+ // 2. (空行后) 校验组名唯一
var names = request.AddonGroups.Select(x => x.Name.Trim()).ToList();
if (names.Count != names.Distinct(StringComparer.OrdinalIgnoreCase).Count())
{
throw new BusinessException(ErrorCodes.Conflict, "加料组名称重复");
}
- // 3. 替换
+ // 3. (空行后) 替换
await productRepository.RemoveAddonGroupsAsync(request.ProductId, tenantId, cancellationToken);
// 重新插入组
var groupEntities = request.AddonGroups.Select(g => new ProductAddonGroup
{
+ TenantId = tenantId,
ProductId = request.ProductId,
Name = g.Name.Trim(),
MinSelect = g.MinSelect,
@@ -57,6 +56,7 @@ public sealed class ReplaceProductAddonsCommandHandler(
var optionEntities = request.AddonGroups
.SelectMany(dto => dto.Options.Select(o => new ProductAddonOption
{
+ TenantId = tenantId,
AddonGroupId = groupIdLookup[dto],
Name = o.Name.Trim(),
ExtraPrice = o.ExtraPrice,
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAttributesCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAttributesCommandHandler.cs
index 9cef4d1..6e10322 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAttributesCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductAttributesCommandHandler.cs
@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -15,33 +14,33 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class ReplaceProductAttributesCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler>
{
///
public async Task> Handle(ReplaceProductAttributesCommand request, CancellationToken cancellationToken)
{
- // 1. 校验商品
- var tenantId = tenantProvider.GetCurrentTenantId();
- var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 校验商品(跨租户)
+ var product = await productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (product is null)
{
throw new BusinessException(ErrorCodes.NotFound, "商品不存在");
}
+ var tenantId = product.TenantId;
- // 2. 组名唯一
+ // 2. (空行后) 组名唯一
var groupNames = request.AttributeGroups.Select(x => x.Name.Trim()).ToList();
if (groupNames.Count != groupNames.Distinct(StringComparer.OrdinalIgnoreCase).Count())
{
throw new BusinessException(ErrorCodes.Conflict, "规格组名称重复");
}
- // 3. 替换
+ // 3. (空行后) 替换
await productRepository.RemoveAttributeGroupsAsync(request.ProductId, tenantId, cancellationToken);
var groupEntities = request.AttributeGroups.Select(g => new ProductAttributeGroup
{
+ TenantId = tenantId,
ProductId = request.ProductId,
Name = g.Name.Trim(),
SelectionType = (Domain.Products.Enums.AttributeSelectionType)g.SelectionType,
@@ -59,6 +58,7 @@ public sealed class ReplaceProductAttributesCommandHandler(
var optionEntities = request.AttributeGroups
.SelectMany(dto => dto.Options.Select(o => new ProductAttributeOption
{
+ TenantId = tenantId,
AttributeGroupId = groupIdLookup[dto],
Name = o.Name.Trim(),
SortOrder = o.SortOrder
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductMediaCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductMediaCommandHandler.cs
index 4c704f4..a2d3918 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductMediaCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductMediaCommandHandler.cs
@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -15,26 +14,26 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class ReplaceProductMediaCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler>
{
///
public async Task> Handle(ReplaceProductMediaCommand request, CancellationToken cancellationToken)
{
- // 1. 校验商品
- var tenantId = tenantProvider.GetCurrentTenantId();
- var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 校验商品(跨租户)
+ var product = await productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (product is null)
{
throw new BusinessException(ErrorCodes.NotFound, "商品不存在");
}
+ var tenantId = product.TenantId;
- // 2. 替换
+ // 2. (空行后) 替换
await productRepository.RemoveMediaAssetsAsync(request.ProductId, tenantId, cancellationToken);
var assets = request.MediaAssets.Select(a => new ProductMediaAsset
{
+ TenantId = tenantId,
ProductId = request.ProductId,
MediaType = a.MediaType,
Url = a.Url.Trim(),
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductPricingRulesCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductPricingRulesCommandHandler.cs
index 8c02739..551b17d 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductPricingRulesCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductPricingRulesCommandHandler.cs
@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -15,26 +14,26 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class ReplaceProductPricingRulesCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler>
{
///
public async Task> Handle(ReplaceProductPricingRulesCommand request, CancellationToken cancellationToken)
{
- // 1. 校验商品
- var tenantId = tenantProvider.GetCurrentTenantId();
- var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 校验商品(跨租户)
+ var product = await productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (product is null)
{
throw new BusinessException(ErrorCodes.NotFound, "商品不存在");
}
+ var tenantId = product.TenantId;
- // 2. 替换
+ // 2. (空行后) 替换
await productRepository.RemovePricingRulesAsync(request.ProductId, tenantId, cancellationToken);
var rules = request.PricingRules.Select(r => new ProductPricingRule
{
+ TenantId = tenantId,
ProductId = request.ProductId,
RuleType = r.RuleType,
ConditionsJson = r.ConditionsJson.Trim(),
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductSkusCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductSkusCommandHandler.cs
index 9f62d45..7bf0ab4 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductSkusCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/ReplaceProductSkusCommandHandler.cs
@@ -6,7 +6,6 @@ using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -15,32 +14,32 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class ReplaceProductSkusCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler>
{
///
public async Task> Handle(ReplaceProductSkusCommand request, CancellationToken cancellationToken)
{
- // 1. 校验商品存在
- var tenantId = tenantProvider.GetCurrentTenantId();
- var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 校验商品存在(跨租户)
+ var product = await productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (product is null)
{
throw new BusinessException(ErrorCodes.NotFound, "商品不存在");
}
+ var tenantId = product.TenantId;
- // 2. 校验 SKU 唯一性
+ // 2. (空行后) 校验 SKU 唯一性
var codes = request.Skus.Select(x => x.SkuCode.Trim()).ToList();
if (codes.Count != codes.Distinct(StringComparer.OrdinalIgnoreCase).Count())
{
throw new BusinessException(ErrorCodes.Conflict, "SKU 编码重复");
}
- // 3. 替换
+ // 3. (空行后) 替换
await productRepository.RemoveSkusAsync(request.ProductId, tenantId, cancellationToken);
var entities = request.Skus.Select(x => new ProductSku
{
+ TenantId = tenantId,
ProductId = request.ProductId,
SkuCode = x.SkuCode.Trim(),
Barcode = x.Barcode?.Trim(),
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UnpublishProductCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UnpublishProductCommandHandler.cs
index 83fe4c8..a05e027 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UnpublishProductCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UnpublishProductCommandHandler.cs
@@ -4,7 +4,6 @@ using TakeoutSaaS.Application.App.Products.Commands;
using TakeoutSaaS.Application.App.Products.Dto;
using TakeoutSaaS.Domain.Products.Enums;
using TakeoutSaaS.Domain.Products.Repositories;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -13,22 +12,20 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class UnpublishProductCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
ILogger logger)
: IRequestHandler
{
///
public async Task Handle(UnpublishProductCommand request, CancellationToken cancellationToken)
{
- // 1. 读取商品
- var tenantId = tenantProvider.GetCurrentTenantId();
- var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 读取商品(跨租户)
+ var product = await productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (product is null)
{
return null;
}
- // 2. 下架
+ // 2. (空行后) 下架
product.Status = ProductStatus.OffShelf;
await productRepository.UpdateProductAsync(product, cancellationToken);
await productRepository.SaveChangesAsync(cancellationToken);
diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UpdateProductCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UpdateProductCommandHandler.cs
index e616788..4a181d3 100644
--- a/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UpdateProductCommandHandler.cs
+++ b/src/Application/TakeoutSaaS.Application/App/Products/Handlers/UpdateProductCommandHandler.cs
@@ -4,7 +4,9 @@ using TakeoutSaaS.Application.App.Products.Commands;
using TakeoutSaaS.Application.App.Products.Dto;
using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
-using TakeoutSaaS.Shared.Abstractions.Tenancy;
+using TakeoutSaaS.Domain.Stores.Repositories;
+using TakeoutSaaS.Shared.Abstractions.Constants;
+using TakeoutSaaS.Shared.Abstractions.Exceptions;
namespace TakeoutSaaS.Application.App.Products.Handlers;
@@ -13,26 +15,37 @@ namespace TakeoutSaaS.Application.App.Products.Handlers;
///
public sealed class UpdateProductCommandHandler(
IProductRepository productRepository,
- ITenantProvider tenantProvider,
+ IStoreRepository storeRepository,
ILogger logger)
: IRequestHandler
{
private readonly IProductRepository _productRepository = productRepository;
- private readonly ITenantProvider _tenantProvider = tenantProvider;
+ private readonly IStoreRepository _storeRepository = storeRepository;
private readonly ILogger _logger = logger;
///
public async Task Handle(UpdateProductCommand request, CancellationToken cancellationToken)
{
- // 1. 读取商品
- var tenantId = _tenantProvider.GetCurrentTenantId();
- var existing = await _productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
+ // 1. 读取商品(跨租户)
+ var existing = await _productRepository.FindByIdAsync(request.ProductId, cancellationToken);
if (existing == null)
{
return null;
}
+ var tenantId = existing.TenantId;
- // 2. 更新字段
+ // 2. (空行后) 校验门店存在且属于同租户
+ var store = await _storeRepository.FindByIdAsync(request.StoreId, tenantId: null, cancellationToken);
+ if (store is null)
+ {
+ throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
+ }
+ if (store.TenantId != tenantId)
+ {
+ throw new BusinessException(ErrorCodes.ValidationFailed, "门店与商品不属于同一租户");
+ }
+
+ // 3. (空行后) 更新字段
existing.StoreId = request.StoreId;
existing.CategoryId = request.CategoryId;
existing.SpuCode = request.SpuCode.Trim();
@@ -52,12 +65,12 @@ public sealed class UpdateProductCommandHandler(
existing.EnableDelivery = request.EnableDelivery;
existing.IsFeatured = request.IsFeatured;
- // 3. 持久化
+ // 4. (空行后) 持久化
await _productRepository.UpdateProductAsync(existing, cancellationToken);
await _productRepository.SaveChangesAsync(cancellationToken);
_logger.LogInformation("更新商品 {ProductId} - {ProductName}", existing.Id, existing.Name);
- // 4. 返回 DTO
+ // 5. (空行后) 返回 DTO
return MapToDto(existing);
}