|
|
@@ -2,6 +2,7 @@ using Admin.NET.Plugin.AiDOP.Dto.S0.Manufacturing;
|
|
|
using Admin.NET.Plugin.AiDOP.Dto.S0.Sales;
|
|
|
using Admin.NET.Plugin.AiDOP.Entity.S0.Manufacturing;
|
|
|
using Admin.NET.Plugin.AiDOP.Infrastructure;
|
|
|
+using Microsoft.Extensions.Logging;
|
|
|
|
|
|
namespace Admin.NET.Plugin.AiDOP.Controllers.S0.Manufacturing;
|
|
|
|
|
|
@@ -13,11 +14,16 @@ public class AdoS0MfgRoutingOpDetailsController : ControllerBase
|
|
|
{
|
|
|
private readonly SqlSugarRepository<AdoS0MfgRoutingOpDetail> _rep;
|
|
|
private readonly AdoS0ReferenceChecker _refChecker;
|
|
|
+ private readonly ILogger<AdoS0MfgRoutingOpDetailsController> _logger;
|
|
|
|
|
|
- public AdoS0MfgRoutingOpDetailsController(SqlSugarRepository<AdoS0MfgRoutingOpDetail> rep, AdoS0ReferenceChecker refChecker)
|
|
|
+ public AdoS0MfgRoutingOpDetailsController(
|
|
|
+ SqlSugarRepository<AdoS0MfgRoutingOpDetail> rep,
|
|
|
+ AdoS0ReferenceChecker refChecker,
|
|
|
+ ILogger<AdoS0MfgRoutingOpDetailsController> logger)
|
|
|
{
|
|
|
_rep = rep;
|
|
|
_refChecker = refChecker;
|
|
|
+ _logger = logger;
|
|
|
}
|
|
|
|
|
|
[HttpGet]
|
|
|
@@ -58,9 +64,17 @@ public class AdoS0MfgRoutingOpDetailsController : ControllerBase
|
|
|
var err = ValidateUpsert(dto);
|
|
|
if (err != null) return BadRequest(new { message = err });
|
|
|
|
|
|
- if (!await _refChecker.MaterialExistsAsync(dto.MaterialCode))
|
|
|
- return AdoS0ApiErrors.InvalidReference(AdoS0ErrorCodes.ReferenceNotFound,
|
|
|
- $"物料编码 '{dto.MaterialCode}' 不存在于物料主数据");
|
|
|
+ // B1 + B2:Create 一律严格校验,禁止降级
|
|
|
+ var matResult = await _refChecker.MaterialExistsInScopeAsync(dto.MaterialCode, dto.CompanyRefId, dto.FactoryRefId);
|
|
|
+ switch (matResult)
|
|
|
+ {
|
|
|
+ case MaterialScopeCheck.NotFound:
|
|
|
+ return AdoS0ApiErrors.InvalidReference(AdoS0ErrorCodes.ReferenceNotFound,
|
|
|
+ $"物料编码 '{dto.MaterialCode}' 不存在于物料主数据");
|
|
|
+ case MaterialScopeCheck.ScopeMiss:
|
|
|
+ return AdoS0ApiErrors.InvalidReference(AdoS0ErrorCodes.InvalidReferenceScope,
|
|
|
+ $"物料编码 '{dto.MaterialCode}' 不属于当前公司/工厂 (CompanyRefId={dto.CompanyRefId}, FactoryRefId={dto.FactoryRefId})");
|
|
|
+ }
|
|
|
|
|
|
if (!await _refChecker.WorkCenterExistsAsync(dto.WorkCenterCode))
|
|
|
return AdoS0ApiErrors.InvalidReference(AdoS0ErrorCodes.ReferenceNotFound,
|
|
|
@@ -78,16 +92,48 @@ public class AdoS0MfgRoutingOpDetailsController : ControllerBase
|
|
|
var err = ValidateUpsert(dto);
|
|
|
if (err != null) return BadRequest(new { message = err });
|
|
|
|
|
|
- if (!await _refChecker.MaterialExistsAsync(dto.MaterialCode))
|
|
|
+ var entity = await _rep.GetByIdAsync(id);
|
|
|
+ if (entity == null) return NotFound();
|
|
|
+
|
|
|
+ // B1 + B2 + 历史兼容降级(D-03 严格条件)
|
|
|
+ var matResult = await _refChecker.MaterialExistsInScopeAsync(dto.MaterialCode, dto.CompanyRefId, dto.FactoryRefId);
|
|
|
+ if (matResult == MaterialScopeCheck.NotFound)
|
|
|
return AdoS0ApiErrors.InvalidReference(AdoS0ErrorCodes.ReferenceNotFound,
|
|
|
$"物料编码 '{dto.MaterialCode}' 不存在于物料主数据");
|
|
|
|
|
|
+ if (matResult == MaterialScopeCheck.ScopeMiss)
|
|
|
+ {
|
|
|
+ // 降级条件(全部满足才允许,对应 D-03 严格条件):
|
|
|
+ // 1. 是 Update(已满足)
|
|
|
+ // 2. DB 原记录 scope 为 0/null/0
|
|
|
+ // 3. 本次未修改 MaterialCode(dto 与 entity 相同)
|
|
|
+ // 4. B1 存在性通过(matResult != NotFound,已满足)
|
|
|
+ var originScopeEmpty = entity.CompanyRefId == 0 && entity.FactoryRefId == 0;
|
|
|
+ var materialUnchanged = string.Equals(entity.MaterialCode, dto.MaterialCode?.Trim(), StringComparison.Ordinal);
|
|
|
+
|
|
|
+ if (originScopeEmpty && materialUnchanged)
|
|
|
+ {
|
|
|
+ _logger.LogWarning(
|
|
|
+ "[B2 Downgrade] Table={TableName} PrimaryKey={PrimaryKey} ReferenceField={ReferenceField} " +
|
|
|
+ "OldValue={OldValue} NewValue={NewValue} CompanyRefId={CompanyRefId} FactoryRefId={FactoryRefId} " +
|
|
|
+ "DowngradeReason={DowngradeReason}",
|
|
|
+ "RoutingOpDetail", entity.Id, "MaterialCode",
|
|
|
+ entity.MaterialCode, dto.MaterialCode,
|
|
|
+ dto.CompanyRefId, dto.FactoryRefId,
|
|
|
+ "LegacyRecord_OriginScopeZero_MaterialUnchanged");
|
|
|
+ // 放行,继续执行写入
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return AdoS0ApiErrors.InvalidReference(AdoS0ErrorCodes.InvalidReferenceScope,
|
|
|
+ $"物料编码 '{dto.MaterialCode}' 不属于当前公司/工厂 (CompanyRefId={dto.CompanyRefId}, FactoryRefId={dto.FactoryRefId})");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (!await _refChecker.WorkCenterExistsAsync(dto.WorkCenterCode))
|
|
|
return AdoS0ApiErrors.InvalidReference(AdoS0ErrorCodes.ReferenceNotFound,
|
|
|
$"工作中心编码 '{dto.WorkCenterCode}' 不存在于工作中心主数据");
|
|
|
|
|
|
- var entity = await _rep.GetByIdAsync(id);
|
|
|
- if (entity == null) return NotFound();
|
|
|
ApplyUpsert(entity, dto);
|
|
|
entity.UpdatedAt = DateTime.Now;
|
|
|
await _rep.AsUpdateable(entity).ExecuteCommandAsync();
|