mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 02:41:06 -04:00
Server nests in Database mode get a read-only status bar label comparing their
open MaterialLedger holds with the sheets they cut, e.g. "Ledger: 2 of 4 held,
2 short". Nothing writes to the ledger and nothing waits on it.
- MaterialLedgerClient.GetHoldsAsync reads GET /api/stock/holds?openNestNestId=
with the closed LedgerHoldsResult set; unknown status strings are kept. The
request plumbing is shared with GetStockAsync.
- LedgerHoldSummary (OpenNest.Data) counts Proposed/Approved/Released/
AwaitingCloseout holds against the plate quantities, skipping the trailing
empty plate as /sheets does.
- NestHoldStatus refreshes on server open, after save, after storage or
Options changes and on label click; it never polls. The tooltip lists holds
in nest units. File-mode, unsaved and ledger-less nests show nothing.
- Setting Has Been Cut in Nest Info with holds still open shows a non-modal
note linking to {ledgerUrl}/Nests/{id}. Posting is not gated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
2.5 KiB
C#
60 lines
2.5 KiB
C#
namespace OpenNest.Data.MaterialLedger;
|
|
|
|
/// <summary>The body of MaterialLedger's <c>GET /api/stock/holds?openNestNestId=</c>.</summary>
|
|
public sealed record LedgerHoldsResponse(Guid OpenNestNestId, IReadOnlyList<LedgerHold>? Holds);
|
|
|
|
/// <summary>
|
|
/// One ML <c>MaterialReservation</c> for a sheet of the nest. Sizes are inches with
|
|
/// <see cref="WidthIn"/> the short side. <see cref="Status"/> stays a string so a new ML
|
|
/// <c>ReservationStatus</c> value still deserializes.
|
|
/// </summary>
|
|
public sealed record LedgerHold(
|
|
long MaterialReservationId,
|
|
string ItemCode,
|
|
decimal WidthIn,
|
|
decimal LengthIn,
|
|
string Status,
|
|
string? LocationCode,
|
|
DateTime CreatedAtUtc);
|
|
|
|
/// <summary>ML <c>ReservationStatus</c> names.</summary>
|
|
public static class LedgerHoldStatuses
|
|
{
|
|
public const string Proposed = "Proposed";
|
|
public const string Approved = "Approved";
|
|
public const string Released = "Released";
|
|
public const string AwaitingCloseout = "AwaitingCloseout";
|
|
public const string ClosedConsumed = "ClosedConsumed";
|
|
public const string ClosedReturned = "ClosedReturned";
|
|
public const string Cancelled = "Cancelled";
|
|
public const string Exception = "Exception";
|
|
|
|
/// <summary>
|
|
/// True for holds that still keep a sheet for the nest and need closing out. Closed,
|
|
/// cancelled, exception and unknown statuses are not open.
|
|
/// </summary>
|
|
public static bool IsOpen(string? status) =>
|
|
string.Equals(status, Proposed, StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(status, Approved, StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(status, Released, StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(status, AwaitingCloseout, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
/// <summary>What a ledger hold request came to. Expected failures are results, never exceptions.</summary>
|
|
public abstract record LedgerHoldsResult
|
|
{
|
|
private LedgerHoldsResult() { }
|
|
|
|
/// <summary>No ledger URL is set on this PC.</summary>
|
|
public sealed record NotConfigured : LedgerHoldsResult;
|
|
|
|
/// <summary>The ledger did not answer usefully: network error, timeout, bad status or body.</summary>
|
|
public sealed record Unreachable(string Reason) : LedgerHoldsResult;
|
|
|
|
/// <summary>The ledger rejected the API key (401/403).</summary>
|
|
public sealed record Unauthorized : LedgerHoldsResult;
|
|
|
|
/// <summary>The nest's holds in every status; empty when ML has none for it.</summary>
|
|
public sealed record Ok(IReadOnlyList<LedgerHold> Holds) : LedgerHoldsResult;
|
|
}
|