refactor(data-access): remove TVP code and simplify SearchModel
- Remove all List<*FilterEntry> properties and *FilterEnabled computed properties from SearchModel - Delete TableValuedParameterExtensions.cs - Delete entire FilterEntries folder and all filter entry model classes - Delete FilterHandlers folder and all filter handler classes - Delete IFilterHandler interface and FilterResult model - Update MisQueryBuilder to use SQL extraction functions instead of model properties - Update SearchProcessor to get ExtractMisData from database using fn_GetSearchExtractMisData - Update DependencyInjection to remove filter handler registrations - Delete obsolete tests for TVP extensions and filter handlers Filter criteria are now stored as JSON in Search.Criteria column and extracted using SQL functions (fn_GetSearch*) during query execution.
This commit is contained in:
-480
@@ -1,480 +0,0 @@
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using Dapper;
|
||||
using JdeScoping.DataAccess.Extensions;
|
||||
using JdeScoping.DataAccess.Models;
|
||||
using JdeScoping.DataAccess.Models.FilterEntries;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace JdeScoping.DataAccess.Tests.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for TableValuedParameterExtensions.
|
||||
/// </summary>
|
||||
public sealed class TableValuedParameterExtensionsTests
|
||||
{
|
||||
#region CreateWorkOrderFilterParameter Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateWorkOrderFilterParameter_ProducesCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter =
|
||||
[
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 12345, ItemNumber = "ABC" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateWorkOrderFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.ShouldNotBeNull();
|
||||
dataTable.Columns.Count.ShouldBe(1);
|
||||
dataTable.Columns.Contains("WorkOrderNumber").ShouldBeTrue();
|
||||
dataTable.Columns["WorkOrderNumber"]!.DataType.ShouldBe(typeof(long));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateWorkOrderFilterParameter_WithEmptyCollection_ProducesEmptyDataTable()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateWorkOrderFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.ShouldNotBeNull();
|
||||
dataTable.Rows.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateWorkOrderFilterParameter_PopulatesCorrectData()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter =
|
||||
[
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 12345 },
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 67890 }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateWorkOrderFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(2);
|
||||
dataTable.Rows[0]["WorkOrderNumber"].ShouldBe(12345L);
|
||||
dataTable.Rows[1]["WorkOrderNumber"].ShouldBe(67890L);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateItemNumberFilterParameter Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateItemNumberFilterParameter_ProducesCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ItemNumberFilter =
|
||||
[
|
||||
new ItemNumberFilterEntry { ItemNumber = "ABC123" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateItemNumberFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.ShouldNotBeNull();
|
||||
dataTable.Columns.Count.ShouldBe(1);
|
||||
dataTable.Columns.Contains("ItemNumber").ShouldBeTrue();
|
||||
dataTable.Columns["ItemNumber"]!.DataType.ShouldBe(typeof(string));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateItemNumberFilterParameter_WithEmptyCollection_ProducesEmptyDataTable()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ItemNumberFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateItemNumberFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateProfitCenterFilterParameter Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateProfitCenterFilterParameter_ProducesCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ProfitCenterFilter =
|
||||
[
|
||||
new ProfitCenterFilterEntry { Code = "PC001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateProfitCenterFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Columns.Count.ShouldBe(1);
|
||||
dataTable.Columns.Contains("Code").ShouldBeTrue();
|
||||
dataTable.Columns["Code"]!.DataType.ShouldBe(typeof(string));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateProfitCenterFilterParameter_WithEmptyCollection_ProducesEmptyDataTable()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ProfitCenterFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateProfitCenterFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateWorkCenterFilterParameter Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateWorkCenterFilterParameter_ProducesCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkCenterFilter =
|
||||
[
|
||||
new WorkCenterFilterEntry { Code = "WC001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateWorkCenterFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Columns.Count.ShouldBe(1);
|
||||
dataTable.Columns.Contains("Code").ShouldBeTrue();
|
||||
dataTable.Columns["Code"]!.DataType.ShouldBe(typeof(string));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateWorkCenterFilterParameter_WithEmptyCollection_ProducesEmptyDataTable()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkCenterFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateWorkCenterFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateComponentLotFilterParameter Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateComponentLotFilterParameter_ProducesCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateComponentLotFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Columns.Count.ShouldBe(2);
|
||||
dataTable.Columns.Contains("ComponentLotNumber").ShouldBeTrue();
|
||||
dataTable.Columns.Contains("ItemNumber").ShouldBeTrue();
|
||||
dataTable.Columns["ComponentLotNumber"]!.DataType.ShouldBe(typeof(string));
|
||||
dataTable.Columns["ItemNumber"]!.DataType.ShouldBe(typeof(string));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateComponentLotFilterParameter_WithEmptyCollection_ProducesEmptyDataTable()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateComponentLotFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateComponentLotFilterParameter_PopulatesCorrectData()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" },
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT002", ItemNumber = "ITEM002" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateComponentLotFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(2);
|
||||
dataTable.Rows[0]["ComponentLotNumber"].ShouldBe("LOT001");
|
||||
dataTable.Rows[0]["ItemNumber"].ShouldBe("ITEM001");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateOperatorFilterParameter Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateOperatorFilterParameter_ProducesCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
OperatorFilter =
|
||||
[
|
||||
new OperatorFilterEntry { UserId = "USER01", AddressNumber = 123 }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateOperatorFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Columns.Count.ShouldBe(1);
|
||||
dataTable.Columns.Contains("UserName").ShouldBeTrue();
|
||||
dataTable.Columns["UserName"]!.DataType.ShouldBe(typeof(string));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateOperatorFilterParameter_WithEmptyCollection_ProducesEmptyDataTable()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
OperatorFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateOperatorFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateItemOperationMisFilterParameter Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateItemOperationMisFilterParameter_ProducesCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ItemOperationMisFilter =
|
||||
[
|
||||
new ItemOperationMisFilterEntry
|
||||
{
|
||||
ItemNumber = "ITEM001",
|
||||
OperationNumber = "010",
|
||||
MisNumber = "MIS001",
|
||||
MisRevision = "A"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateItemOperationMisFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Columns.Count.ShouldBe(4);
|
||||
dataTable.Columns.Contains("ItemNumber").ShouldBeTrue();
|
||||
dataTable.Columns.Contains("OperationNumber").ShouldBeTrue();
|
||||
dataTable.Columns.Contains("MisNumber").ShouldBeTrue();
|
||||
dataTable.Columns.Contains("MisRevision").ShouldBeTrue();
|
||||
|
||||
dataTable.Columns["ItemNumber"]!.DataType.ShouldBe(typeof(string));
|
||||
dataTable.Columns["OperationNumber"]!.DataType.ShouldBe(typeof(string));
|
||||
dataTable.Columns["MisNumber"]!.DataType.ShouldBe(typeof(string));
|
||||
dataTable.Columns["MisRevision"]!.DataType.ShouldBe(typeof(string));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateItemOperationMisFilterParameter_WithEmptyCollection_ProducesEmptyDataTable()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ItemOperationMisFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateItemOperationMisFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateItemOperationMisFilterParameter_PopulatesCorrectData()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ItemOperationMisFilter =
|
||||
[
|
||||
new ItemOperationMisFilterEntry
|
||||
{
|
||||
ItemNumber = "ITEM001",
|
||||
OperationNumber = "010",
|
||||
MisNumber = "MIS001",
|
||||
MisRevision = "A"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var param = model.CreateItemOperationMisFilterParameter();
|
||||
var dataTable = ExtractDataTable(param);
|
||||
|
||||
// Assert
|
||||
dataTable.Rows.Count.ShouldBe(1);
|
||||
dataTable.Rows[0]["ItemNumber"].ShouldBe("ITEM001");
|
||||
dataTable.Rows[0]["OperationNumber"].ShouldBe("010");
|
||||
dataTable.Rows[0]["MisNumber"].ShouldBe("MIS001");
|
||||
dataTable.Rows[0]["MisRevision"].ShouldBe("A");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the underlying DataTable from a Dapper table-valued parameter.
|
||||
/// Uses reflection to access internal fields across different Dapper versions.
|
||||
/// </summary>
|
||||
private static DataTable ExtractDataTable(SqlMapper.ICustomQueryParameter param)
|
||||
{
|
||||
// The TableValuedParameter wraps a DataTable - try multiple field/property names
|
||||
// across different Dapper versions
|
||||
var type = param.GetType();
|
||||
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
|
||||
|
||||
// Try field names used in different Dapper versions
|
||||
var fieldNames = new[] { "_table", "table", "Table", "_dataTable", "dataTable" };
|
||||
foreach (var fieldName in fieldNames)
|
||||
{
|
||||
var field = type.GetField(fieldName, bindingFlags);
|
||||
if (field != null && field.FieldType == typeof(DataTable))
|
||||
{
|
||||
var value = field.GetValue(param);
|
||||
if (value is DataTable dt)
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
// Try property names
|
||||
var propertyNames = new[] { "Table", "DataTable", "table", "_table" };
|
||||
foreach (var propName in propertyNames)
|
||||
{
|
||||
var prop = type.GetProperty(propName, bindingFlags);
|
||||
if (prop != null && prop.PropertyType == typeof(DataTable))
|
||||
{
|
||||
var value = prop.GetValue(param);
|
||||
if (value is DataTable dt)
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort: scan all fields
|
||||
foreach (var field in type.GetFields(bindingFlags))
|
||||
{
|
||||
if (field.FieldType == typeof(DataTable))
|
||||
{
|
||||
var value = field.GetValue(param);
|
||||
if (value is DataTable dt)
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan all properties
|
||||
foreach (var prop in type.GetProperties(bindingFlags))
|
||||
{
|
||||
if (prop.PropertyType == typeof(DataTable))
|
||||
{
|
||||
var value = prop.GetValue(param);
|
||||
if (value is DataTable dt)
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Could not extract DataTable from {type.FullName}. " +
|
||||
$"Fields: {string.Join(", ", type.GetFields(bindingFlags).Select(f => f.Name))}. " +
|
||||
$"Properties: {string.Join(", ", type.GetProperties(bindingFlags).Select(p => p.Name))}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
-196
@@ -1,196 +0,0 @@
|
||||
using JdeScoping.DataAccess.FilterHandlers;
|
||||
using JdeScoping.DataAccess.Models;
|
||||
using JdeScoping.DataAccess.Models.FilterEntries;
|
||||
using Shouldly;
|
||||
using SqlKata.Compilers;
|
||||
using Xunit;
|
||||
|
||||
namespace JdeScoping.DataAccess.Tests.FilterHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for ComponentLotFilterHandler.
|
||||
/// </summary>
|
||||
public sealed class ComponentLotFilterHandlerTests
|
||||
{
|
||||
private readonly SqlServerCompiler _compiler = new();
|
||||
private readonly ComponentLotFilterHandler _handler = new();
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_WithComponentLotFilters_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.IsEnabled(model);
|
||||
|
||||
// Assert
|
||||
result.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_WithEmptyComponentLotFilters_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.IsEnabled(model);
|
||||
|
||||
// Assert
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_WithNullComponentLotFilters_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel();
|
||||
|
||||
// Act
|
||||
var result = _handler.IsEnabled(model);
|
||||
|
||||
// Assert
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_ContainsWorkOrderComponentJoin()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
result.ShouldNotBeNull();
|
||||
result.SetupSql.ShouldNotBeEmpty();
|
||||
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
allSql.ShouldContain("dbo.WorkOrderComponent AS woc");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_ContainsLotUsageJoin()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
allSql.ShouldContain("dbo.LotUsage AS lu");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_SetsCARDEXFlag()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
// CARDEX flag is set (not PartsList) per the ComponentLotFilterHandler implementation
|
||||
allSql.ShouldContain("TARGET.CARDEX = 1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_DoesNotSetPartsListFlag()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
// ComponentLotFilterHandler sets CARDEX, not PartsList
|
||||
allSql.ShouldNotContain("PartsList = 1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_ContainsSplitOrderLogic()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
allSql.ShouldContain("SplitOrder");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_Parameters_ContainsComponentLotFilterParameter()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
ComponentLotFilter =
|
||||
[
|
||||
new ComponentLotFilterEntry { LotNumber = "LOT001", ItemNumber = "ITEM001" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
result.Parameters.ShouldContainKey("p_ComponentLotFilter");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Priority_ReturnsExpectedValue()
|
||||
{
|
||||
// Assert
|
||||
_handler.Priority.ShouldBe(30);
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
using JdeScoping.DataAccess.FilterHandlers;
|
||||
using JdeScoping.DataAccess.Models;
|
||||
using JdeScoping.DataAccess.Models.FilterEntries;
|
||||
using Shouldly;
|
||||
using SqlKata.Compilers;
|
||||
using Xunit;
|
||||
|
||||
namespace JdeScoping.DataAccess.Tests.FilterHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for WorkOrderFilterHandler.
|
||||
/// </summary>
|
||||
public sealed class WorkOrderFilterHandlerTests
|
||||
{
|
||||
private readonly SqlServerCompiler _compiler = new();
|
||||
private readonly WorkOrderFilterHandler _handler = new();
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_WithWorkOrderFilters_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter =
|
||||
[
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 12345, ItemNumber = "ABC123" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.IsEnabled(model);
|
||||
|
||||
// Assert
|
||||
result.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_WithEmptyWorkOrderFilters_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter = []
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.IsEnabled(model);
|
||||
|
||||
// Assert
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_WithNullWorkOrderFilters_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel();
|
||||
|
||||
// Act
|
||||
var result = _handler.IsEnabled(model);
|
||||
|
||||
// Assert
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_ContainsMerge()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter =
|
||||
[
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 12345, ItemNumber = "ABC123" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
result.ShouldNotBeNull();
|
||||
result.SetupSql.ShouldNotBeEmpty();
|
||||
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
allSql.ShouldContain("MERGE #Temp_WO AS TARGET");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_ContainsManuallySpecified()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter =
|
||||
[
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 12345, ItemNumber = "ABC123" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
allSql.ShouldContain("ManuallySpecified = 1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_GeneratedSql_ContainsSplitOrderLogic()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter =
|
||||
[
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 12345, ItemNumber = "ABC123" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
var allSql = string.Join("\n", result.SetupSql);
|
||||
allSql.ShouldContain("SplitOrder");
|
||||
allSql.ShouldContain("ParentWorkOrderNumber");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_Parameters_ContainsWorkOrderFilterParameter()
|
||||
{
|
||||
// Arrange
|
||||
var model = new SearchModel
|
||||
{
|
||||
WorkOrderFilter =
|
||||
[
|
||||
new WorkOrderFilterEntry { WorkOrderNumber = 12345, ItemNumber = "ABC123" }
|
||||
]
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _handler.Apply(model, _compiler);
|
||||
|
||||
// Assert
|
||||
result.Parameters.ShouldContainKey("p_WorkOrderFilter");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Priority_ReturnsExpectedValue()
|
||||
{
|
||||
// Assert
|
||||
_handler.Priority.ShouldBe(10);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user