Files

137 lines
5.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using DongfangHydro.Dashboard.Api.Data;
using DongfangHydro.Dashboard.Api.Domain;
using DongfangHydro.Dashboard.Api.Importing;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace DongfangHydro.Dashboard.Tests;
public sealed class BomImportServiceTests
{
[Fact]
public void Order_code_index_is_not_unique_because_source_document_is_the_import_identity()
{
var options = new DbContextOptionsBuilder<DashboardDbContext>()
.UseInMemoryDatabase($"bom-model-{Guid.NewGuid():N}")
.Options;
using var dbContext = new DashboardDbContext(options);
var orderType = dbContext.Model.FindEntityType(typeof(ProductionOrder))!;
var codeIndex = Assert.Single(orderType.GetIndexes(), index =>
index.Properties.Count == 1 && index.Properties[0].Name == nameof(ProductionOrder.Code));
Assert.False(codeIndex.IsUnique);
}
[Fact]
public async Task Import_replaces_matching_source_purges_demo_and_is_idempotent()
{
var options = new DbContextOptionsBuilder<DashboardDbContext>()
.UseInMemoryDatabase($"bom-import-{Guid.NewGuid():N}")
.Options;
await using var dbContext = new DashboardDbContext(options);
await dbContext.Database.EnsureCreatedAsync();
dbContext.ProductionOrders.AddRange(
CreateOrder("MO-DEMO", "demo", string.Empty),
CreateOrder("2437-OLD", "excel", "SG2026-06-033"),
CreateOrder("KEEP-001", "manual", "OTHER-DOC"));
await dbContext.SaveChangesAsync();
var service = new BomImportService(dbContext);
var document = CreateDocument();
var first = await service.ImportAsync(document, purgeDemo: true, CancellationToken.None);
var progressedNode = await dbContext.ProductionNodes.SingleAsync(node => node.SourceRow == 6);
progressedNode.CompletedQty = 1;
progressedNode.Progress = 50;
progressedNode.Status = "in_progress";
await dbContext.SaveChangesAsync();
var second = await service.ImportAsync(document, purgeDemo: true, CancellationToken.None);
Assert.Equal(1, first.RemovedDemoOrders);
Assert.Equal(1, first.ReplacedOrders);
Assert.Equal(0, second.ReplacedOrders);
Assert.Equal(2, second.TotalOrders);
Assert.Equal(2, await dbContext.ProductionOrders.CountAsync());
Assert.DoesNotContain(await dbContext.ProductionOrders.ToListAsync(), order => order.DataSource == "demo");
Assert.Contains(await dbContext.ProductionOrders.ToListAsync(), order => order.Code == "KEEP-001");
var importedOrder = await dbContext.ProductionOrders.SingleAsync(
order => order.SourceDocumentCode == "SG2026-06-033");
Assert.Equal("2437-QM0201", importedOrder.Code);
Assert.Equal("excel", importedOrder.DataSource);
Assert.Null(importedOrder.PlannedStart);
Assert.Null(importedOrder.PlannedEnd);
var nodes = await dbContext.ProductionNodes
.Where(node => node.OrderId == importedOrder.Id)
.OrderBy(node => node.Level)
.ThenBy(node => node.SourceRow)
.ToListAsync();
Assert.Equal(3, nodes.Count);
Assert.Equal("order", nodes[0].NodeType);
Assert.Equal("part", nodes[1].NodeType);
Assert.Equal("material", nodes[2].NodeType);
Assert.Equal(nodes[0].Id, nodes[1].ParentNodeId);
Assert.Equal(nodes[1].Id, nodes[2].ParentNodeId);
Assert.Equal(1, nodes.Single(node => node.SourceRow == 6).CompletedQty);
Assert.Equal(50, nodes.Single(node => node.SourceRow == 6).Progress);
Assert.Equal("in_progress", nodes.Single(node => node.SourceRow == 6).Status);
var quota = await dbContext.MaterialQuotas.SingleAsync(item => item.OrderId == importedOrder.Id);
Assert.Equal("钢板", quota.Category);
Assert.Equal(33.61m, quota.NetWeight);
Assert.Equal(9, quota.SourceRow);
var forced = await service.ImportAsync(
document,
purgeDemo: true,
CancellationToken.None,
forceReplace: true);
Assert.Equal(1, forced.ReplacedOrders);
Assert.False(forced.SkippedUnchanged);
Assert.Equal(0, (await dbContext.ProductionNodes.SingleAsync(node => node.SourceRow == 6)).Progress);
}
private static ProductionOrder CreateOrder(string code, string dataSource, string sourceDocumentCode)
{
return new ProductionOrder
{
Id = Guid.NewGuid(),
Code = code,
ProductName = code,
DataSource = dataSource,
SourceDocumentCode = sourceDocumentCode,
BatchQty = 1,
RequiredQty = 1,
Status = "waiting",
RiskLevel = "normal",
CreatedAt = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow,
};
}
private static BomImportDocument CreateDocument()
{
return new BomImportDocument(
new BomImportMetadata(
"SG2026-06-033",
"2437-QM0201",
"青峪口水库工程",
"青峪口尾水单向门机 2×160/10",
"电站尾水2×160kN/100kN单向门式启闭机",
1,
"bom.xlsx",
new string('a', 64)),
[
new BomImportNode(2, null, "1", "P-01", "主起升机构", "", 1, "部件", 10, 10, "", 1, "part", "self_made"),
new BomImportNode(6, 2, "1.1", "GB/T700", "钢板", "δ10", 2, "Q235B", 5, 10, "", 2, "material", "purchased"),
],
[
new MaterialQuotaImportRow(9, "钢板", "1", "1010100182", "钢板/Q235B", "δ2-1500", "kg", null, 33.61m, 35.6266m, "无", ""),
],
2,
[]);
}
}