mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-29 22:51:06 -04:00
Auto Nest leaves out ledger item codes already on other open server nests, and save and post re-check a nest's codes before going on. - Server: GET /api/nests/stock-item-codes?exclude= lists the codes on non-deleted Draft, Quote and To Be Cut nests. Codes are stored in nest_stock_codes (schema v14) at every archive write; the upgrade reads each current archive once. - Data: INestRepository.GetStockCodesInUseAsync, LedgerCodesInUse (5 s, failures become an unknown answer), the pure LedgerCodeFilter for ledger rows (reusable by release-time nesting) and LedgerCodeCheck for the re-check. - Desktop: the Auto Nest ledger summary counts "(N on other nests)" or says other nests were not checked. Save, Save As and post open Ledger Stock Changed when codes are taken: proceed after a per-attempt acknowledgement, remove the codes (undoable), or cancel. A ledger that cannot be read skips the check with a status note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
106 lines
3.6 KiB
C#
106 lines
3.6 KiB
C#
using OpenNest.Data.MaterialLedger;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Tests.Data;
|
|
|
|
/// <summary>
|
|
/// Before save and post, a nest's codes are checked against the ledger's free stock (plus the
|
|
/// nest's own open holds) and other open nests; conflicting codes can be taken off the plates.
|
|
/// </summary>
|
|
public class LedgerCodeCheckTests
|
|
{
|
|
[Fact]
|
|
public void FreeCodesOnNoOtherNest_AreClear()
|
|
{
|
|
var plates = Plates(["S-1"], ["B-1", "B-1"]);
|
|
|
|
var conflicts = LedgerCodeCheck.Find(plates, [Item("S-1", 1), Item("B-1", 2)], null,
|
|
LedgerCodesInUse.Known([]));
|
|
|
|
Assert.Empty(conflicts);
|
|
}
|
|
|
|
[Fact]
|
|
public void TakenCodes_AreReportedPerPlateWithTheirReason()
|
|
{
|
|
var plates = Plates(["GONE"], ["B-1", "B-1"], ["B-1", "OTHER"]);
|
|
var inUse = LedgerCodesInUse.Known([LedgerCodeFilterTests.Use("OTHER", "2026-0042")]);
|
|
|
|
var conflicts = LedgerCodeCheck.Find(plates, [Item("B-1", 2), Item("OTHER", 1)], null, inUse);
|
|
|
|
Assert.Equal(
|
|
[
|
|
(1, "GONE", "Not free in MaterialLedger"),
|
|
(2, "B-1", "Only 2 of the 3 sheets needed free in MaterialLedger"),
|
|
(3, "B-1", "Only 2 of the 3 sheets needed free in MaterialLedger"),
|
|
(3, "OTHER", "On nest 2026-0042"),
|
|
], conflicts.Select(c => (c.PlateNumber, c.ItemCode, c.Reason)));
|
|
}
|
|
|
|
[Fact]
|
|
public void BothReasons_AreJoined()
|
|
{
|
|
var inUse = LedgerCodesInUse.Known([LedgerCodeFilterTests.Use("S-1", "B"), LedgerCodeFilterTests.Use("S-1", "A")]);
|
|
|
|
var conflict = Assert.Single(LedgerCodeCheck.Find(Plates(["S-1"]), [], null, inUse));
|
|
|
|
Assert.Equal("Not free in MaterialLedger; on nests A, B", conflict.Reason);
|
|
}
|
|
|
|
[Fact]
|
|
public void TheNestsOwnOpenHolds_KeepItsSheets()
|
|
{
|
|
var plates = Plates(["S-1"], ["B-1", "B-1"]);
|
|
LedgerHold[] holds =
|
|
[
|
|
Hold("S-1", LedgerHoldStatuses.Approved),
|
|
Hold("B-1", LedgerHoldStatuses.Proposed),
|
|
Hold("B-1", LedgerHoldStatuses.Cancelled),
|
|
];
|
|
|
|
var conflicts = LedgerCodeCheck.Find(plates, [Item("B-1", 1)], holds, LedgerCodesInUse.Known([]));
|
|
|
|
Assert.Empty(conflicts);
|
|
}
|
|
|
|
[Fact]
|
|
public void UnknownCodesInUse_CheckTheLedgerAlone()
|
|
{
|
|
var conflicts = LedgerCodeCheck.Find(Plates(["S-1"]), [Item("S-1", 1)], null,
|
|
LedgerCodesInUse.Unknown("nests are saved as files"));
|
|
|
|
Assert.Empty(conflicts);
|
|
}
|
|
|
|
[Fact]
|
|
public void Remove_TakesEveryCopyOffAndKeepsTheRestInOrder()
|
|
{
|
|
var plates = Plates(["B-1", "S-1", "B-1"], ["S-2"]);
|
|
|
|
var removed = LedgerCodeCheck.Remove(plates, ["B-1"]);
|
|
|
|
Assert.Equal(2, removed);
|
|
Assert.Equal(["S-1"], plates[0].StockItemCodes);
|
|
Assert.Equal(3, plates[0].Quantity);
|
|
Assert.Equal(["S-2"], plates[1].StockItemCodes);
|
|
Assert.True(LedgerCodeCheck.HasCodes(plates));
|
|
LedgerCodeCheck.Remove(plates, ["S-1", "S-2"]);
|
|
Assert.False(LedgerCodeCheck.HasCodes(plates));
|
|
}
|
|
|
|
private static List<Plate> Plates(params string[][] codes) =>
|
|
codes.Select(c =>
|
|
{
|
|
var plate = new Plate(new Size(48, 96)) { Quantity = c.Length };
|
|
plate.StockItemCodes = c;
|
|
return plate;
|
|
}).ToList();
|
|
|
|
private static LedgerStockItem Item(string code, int quantity) =>
|
|
new(code, 7, LedgerItemKinds.FullSheet, 48, 96, quantity, LedgerItemShapes.Rectangular, "R1", "Rack 1",
|
|
null, null, DateTime.UtcNow);
|
|
|
|
private static LedgerHold Hold(string code, string status) =>
|
|
new(1, code, 48, 96, status, "R1", DateTime.UtcNow);
|
|
}
|