serial numbers
This commit is contained in:
@@ -7,12 +7,16 @@ namespace ERPCore.Dtos.Grn;
|
||||
|
||||
public sealed record GrnLineWarrantyNumberDto(string WarrantyNo, int WarrantyPeriodMonths);
|
||||
|
||||
/// <summary>A serial captured on a GRN line; <see cref="SerialId"/> is set once the GRN is confirmed.</summary>
|
||||
public sealed record GrnLineSerialDto(string SerialNo, int? SerialId);
|
||||
|
||||
public sealed record GrnLineDto(
|
||||
int GrnLineId, int? PoLineId, int ItemId, int? BinId,
|
||||
decimal Qty, decimal UnitCost, decimal? PoUnitPrice,
|
||||
decimal DiscountPct, decimal NetUnitCost, decimal VatPct, decimal VatAmount,
|
||||
decimal ReceivedValue, decimal LineTotal, decimal PriceVariance,
|
||||
HoldStatus HoldStatus, int? BatchId, IReadOnlyList<GrnLineWarrantyNumberDto> WarrantyNumbers);
|
||||
HoldStatus HoldStatus, int? BatchId, IReadOnlyList<GrnLineWarrantyNumberDto> WarrantyNumbers,
|
||||
string? BatchNo, DateOnly? BatchExpiryDate, IReadOnlyList<GrnLineSerialDto> Serials);
|
||||
|
||||
public sealed record GrnDto(
|
||||
int GrnId, string DocNo, int? PoId, int VendorId, int WarehouseId, int BranchId, GrnStatus Status,
|
||||
@@ -70,9 +74,15 @@ public sealed class CreateGrnLineInput
|
||||
public BatchInput? Batch { get; set; }
|
||||
/// <summary>
|
||||
/// Required, one per unit (count must equal <see cref="Qty"/>), when the item is
|
||||
/// warranty-tracked (<c>Item.Warranty == Warranty.Warranty</c>). Ignored otherwise.
|
||||
/// warranty-tracked (<c>Item.Warranty == Warranty.Warranty</c>) and not serial-tracked —
|
||||
/// a serial item's serial is its warranty identity. Ignored otherwise.
|
||||
/// </summary>
|
||||
public List<string>? WarrantyNumbers { get; set; }
|
||||
/// <summary>
|
||||
/// Required, one per unit (count must equal <see cref="Qty"/>, so Qty must be whole), when the
|
||||
/// item is serial-tracked (<c>Item.TrackingMode == Serial</c>). Rejected for any other item.
|
||||
/// </summary>
|
||||
public List<string>? SerialNumbers { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateGrnRequest
|
||||
|
||||
@@ -25,6 +25,12 @@ public sealed class CreatePurchaseReturnLineInput
|
||||
public int? GrnLineId { get; set; }
|
||||
[Required] public int ItemId { get; set; }
|
||||
[Range(0.0001, double.MaxValue)] public decimal Qty { get; set; }
|
||||
/// <summary>
|
||||
/// Serials sent back, for a serial-tracked item — one per unit, each at the return warehouse
|
||||
/// (InStock or Damaged; for a rejected GRN line, received on that line). They become
|
||||
/// <c>ReturnedToVendor</c>. Rejected for any other item.
|
||||
/// </summary>
|
||||
public List<int>? SerialIds { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreatePurchaseReturnRequest
|
||||
|
||||
@@ -7,7 +7,11 @@ public sealed record SalesInvoiceLineDto(
|
||||
int SalesInvoiceLineId, int ItemId, string Description, decimal Qty, decimal FreeQty,
|
||||
int WarehouseId, decimal UnitPrice, decimal BaseCost, string PriceSource, decimal DiscountPct,
|
||||
decimal DiscountAmount, SalesDiscountMode DiscountMode, decimal NetUnitPrice, decimal LineTotal,
|
||||
decimal TaxPct, decimal TaxAmount, bool IsFreeIssue, int? ParentLineId);
|
||||
decimal TaxPct, decimal TaxAmount, bool IsFreeIssue, int? ParentLineId,
|
||||
int? BatchId, IReadOnlyList<SalesLineSerialDto> Serials);
|
||||
|
||||
/// <summary>A serial chosen on (or sold by) a sales line.</summary>
|
||||
public sealed record SalesLineSerialDto(int SerialId, string SerialNo);
|
||||
|
||||
public sealed record SalesInvoiceTotalsDto(
|
||||
decimal Subtotal, decimal DiscountTotal, decimal FreeQtyTotal, decimal TaxTotal, decimal GrandTotal,
|
||||
@@ -95,6 +99,13 @@ public sealed class CreateSalesInvoiceLineRequest
|
||||
[Range(0, 100)] public decimal? TaxPct { get; set; }
|
||||
public bool IsFreeIssue { get; set; }
|
||||
public int? ParentLineId { get; set; }
|
||||
/// <summary>Pins the line to one batch (must belong to the item, not expired). Omit to let posting pick FEFO.</summary>
|
||||
public int? BatchId { get; set; }
|
||||
/// <summary>
|
||||
/// Serials sold on this line — required for a serial-tracked item, one per unit of
|
||||
/// Qty + FreeQty, each InStock at the line warehouse. Rejected for any other item.
|
||||
/// </summary>
|
||||
public List<int>? SerialIds { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateSalesInvoiceRequest
|
||||
|
||||
@@ -5,7 +5,17 @@ namespace ERPCore.Dtos.Sales;
|
||||
|
||||
// Responses -----------------------------------------------------------------
|
||||
|
||||
public sealed record SalesReturnLineDto(int ReturnLineId, int? SalesInvoiceLineId, int ItemId, decimal Qty);
|
||||
public sealed record SalesReturnLineDto(
|
||||
int ReturnLineId, int? SalesInvoiceLineId, int ItemId, decimal Qty,
|
||||
int? BatchId, IReadOnlyList<SalesLineSerialDto> Serials);
|
||||
|
||||
/// <summary>
|
||||
/// What one posted sales invoice line issued, net of returns — the batches/serials a return
|
||||
/// against it can take back.
|
||||
/// </summary>
|
||||
public sealed record SalesLineAllocationDto(
|
||||
int? BatchId, string? BatchNo, DateOnly? ExpiryDate, int? SerialId, string? SerialNo,
|
||||
decimal Qty, decimal QtyReturned);
|
||||
|
||||
public sealed record SalesReturnDto(
|
||||
int ReturnId, string DocNo, int CustomerId, int WarehouseId, int ReasonCodeId, ReturnStatus Status,
|
||||
@@ -22,7 +32,8 @@ public sealed record SalesReturnSummaryDto(
|
||||
/// whatever has already been returned against it. The invoice line's own <c>Qty</c>
|
||||
/// is never mutated by a return, so this is computed on read from return history.
|
||||
/// </summary>
|
||||
public sealed record SalesInvoiceLineRemainingDto(int SalesInvoiceLineId, decimal RemainingQty);
|
||||
public sealed record SalesInvoiceLineRemainingDto(
|
||||
int SalesInvoiceLineId, decimal RemainingQty, IReadOnlyList<SalesLineAllocationDto> Allocations);
|
||||
|
||||
// Requests --------------------------------------------------------------------
|
||||
|
||||
@@ -32,6 +43,16 @@ public sealed class CreateSalesReturnLineInput
|
||||
public int? SalesInvoiceLineId { get; set; }
|
||||
[Required] public int ItemId { get; set; }
|
||||
[Range(0.0001, double.MaxValue)] public decimal Qty { get; set; }
|
||||
/// <summary>
|
||||
/// Batch to restock into. Optional when the invoice line issued a single batch (it is used);
|
||||
/// required for a batch-tracked item otherwise, and must be one the line issued.
|
||||
/// </summary>
|
||||
public int? BatchId { get; set; }
|
||||
/// <summary>
|
||||
/// Returned serials of a serial-tracked item — one per unit, each Sold (and, with an invoice
|
||||
/// line, sold on that line). Rejected for any other item.
|
||||
/// </summary>
|
||||
public List<int>? SerialIds { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateSalesReturnRequest
|
||||
@@ -40,5 +61,10 @@ public sealed class CreateSalesReturnRequest
|
||||
[Required] public int WarehouseId { get; set; }
|
||||
/// <summary>Nullable so an omitted value is a distinct <c>REASON_CODE_REQUIRED</c> error.</summary>
|
||||
public int? ReasonCodeId { get; set; }
|
||||
/// <summary>
|
||||
/// Returned serials become <c>Damaged</c> (not resaleable) instead of <c>InStock</c>. Omit to
|
||||
/// derive it from the reason: <c>DEF</c> (Defective) and <c>QREJ</c> (Quality Reject) mean damaged.
|
||||
/// </summary>
|
||||
public bool? MarkDamaged { get; set; }
|
||||
[Required, MinLength(1)] public List<CreateSalesReturnLineInput> Lines { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public sealed record SalesSlipLineDto(
|
||||
int WarehouseId, decimal UnitPrice, decimal BaseCost, string PriceSource, decimal DiscountPct,
|
||||
decimal DiscountAmount, SalesDiscountMode DiscountMode, decimal NetUnitPrice, decimal LineTotal,
|
||||
decimal TaxPct, decimal TaxAmount, bool IsFreeIssue, int? ParentLineId,
|
||||
int? BatchId, int? SerialId);
|
||||
int? BatchId, int? SerialId, IReadOnlyList<SalesLineSerialDto> Serials);
|
||||
|
||||
public sealed record SalesSlipTotalsDto(
|
||||
decimal Subtotal, decimal DiscountTotal, decimal FreeQtyTotal, decimal TaxTotal, decimal GrandTotal,
|
||||
@@ -62,8 +62,13 @@ public sealed class CreateSalesSlipLineRequest
|
||||
public int? ParentLineId { get; set; }
|
||||
/// <summary>Pins the line to a specific batch (must belong to <see cref="ItemId"/>), consumed via FIFO.</summary>
|
||||
public int? BatchId { get; set; }
|
||||
/// <summary>Pins the line to a specific serial (must belong to <see cref="ItemId"/>); marked Sold on posting.</summary>
|
||||
/// <summary>Legacy single-serial pin — treated as <c>SerialIds = [SerialId]</c> when <see cref="SerialIds"/> is empty.</summary>
|
||||
public int? SerialId { get; set; }
|
||||
/// <summary>
|
||||
/// Serials sold on this line — required for a serial-tracked item, one per unit of
|
||||
/// Qty + FreeQty, each InStock at the line warehouse. Marked Sold on posting.
|
||||
/// </summary>
|
||||
public List<int>? SerialIds { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateSalesSlipRequest
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace ERPCore.Dtos.Stock;
|
||||
|
||||
// Responses (docs/11 §5.5) ------------------------------------------------------
|
||||
|
||||
public sealed record AdjustmentLineDto(int AdjLineId, int ItemId, int? BinId, int? BatchId, decimal QtyDelta);
|
||||
public sealed record AdjustmentLineDto(int AdjLineId, int ItemId, int? BinId, int? BatchId, decimal QtyDelta, int? SerialId);
|
||||
|
||||
public sealed record AdjustmentDto(
|
||||
int AdjustmentId, string DocNo, int WarehouseId, int BranchId, int ReasonCodeId, AdjustmentStatus Status,
|
||||
@@ -26,6 +26,16 @@ public sealed class CreateAdjustmentLineInput
|
||||
public int? BatchId { get; set; }
|
||||
/// <summary>Signed base-UOM delta: negative consumes FIFO layers, positive adds stock.</summary>
|
||||
public decimal QtyDelta { get; set; }
|
||||
/// <summary>
|
||||
/// Negative delta on a serial-tracked item: the serials written off (InStock or Damaged at
|
||||
/// the warehouse, one per unit) — they become <c>Scrapped</c>.
|
||||
/// </summary>
|
||||
public List<int>? SerialIds { get; set; }
|
||||
/// <summary>
|
||||
/// Positive delta on a serial-tracked item: the serial numbers found (one per unit) — new
|
||||
/// numbers are created, a known serial that is out of stock is brought back InStock.
|
||||
/// </summary>
|
||||
public List<string>? SerialNos { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateAdjustmentRequest
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using ERPCore.Domain.Enums;
|
||||
|
||||
namespace ERPCore.Dtos.Stock;
|
||||
|
||||
// Item tracking lookups and registers (docs/ITEM_TRACKING_PLAN.md Phases 5, 8, 9).
|
||||
|
||||
/// <summary>Product Configuration tracking switches, as every screen needs them.</summary>
|
||||
public sealed record TrackingSettingsDto(bool SerialNumbersEnabled);
|
||||
|
||||
/// <summary>An issuable serial, for sale/transfer/return pickers.</summary>
|
||||
public sealed record AvailableSerialDto(int SerialId, string SerialNo, int? BatchId, string? BatchNo, SerialStatus Status);
|
||||
|
||||
/// <summary>Issuable stock of one batch at a warehouse (BatchId null = unbatched stock).</summary>
|
||||
public sealed record AvailableBatchDto(int? BatchId, string? BatchNo, DateOnly? ExpiryDate, decimal Qty, int? DaysToExpiry);
|
||||
|
||||
/// <summary>A FEFO pick: <see cref="Qty"/> of <see cref="BatchId"/>.</summary>
|
||||
public sealed record BatchSuggestionDto(int? BatchId, string? BatchNo, DateOnly? ExpiryDate, decimal Qty);
|
||||
|
||||
public sealed record SerialSummaryDto(
|
||||
int SerialId, int ItemId, string Sku, string ItemName, string SerialNo, SerialStatus Status,
|
||||
int? WarehouseId, string? WarehouseName, int? BinId, DateTime? ReceivedAt,
|
||||
int? GrnId, string? GrnDocNo, int? WarrantyPeriodMonths);
|
||||
|
||||
public sealed record SerialMovementDto(
|
||||
int SerialMovementId, string SourceDocType, int SourceDocId, SerialStatus Status,
|
||||
int? FromWarehouseId, int? WarehouseId, int UserId, DateTime CreatedAt);
|
||||
|
||||
public sealed record SerialDetailDto(
|
||||
SerialSummaryDto Serial, IReadOnlyList<SerialMovementDto> History, IReadOnlyList<WarrantyRegistrationDto> Warranties);
|
||||
|
||||
public sealed record WarrantyRegistrationDto(
|
||||
int WarrantyRegistrationId, int ItemId, string Sku, string ItemName, int? SerialId, string? SerialNo,
|
||||
int CustomerId, string CustomerName, string SourceDocType, int SourceDocId, int SourceLineId,
|
||||
decimal Qty, DateOnly StartDate, int PeriodMonths, DateOnly EndDate, WarrantyStatus Status,
|
||||
int DaysRemaining, bool IsExpired);
|
||||
|
||||
/// <summary>Stock on hand per batch (with expiry), for the batch / expiry report.</summary>
|
||||
public sealed record BatchStockDto(
|
||||
int ItemId, string Sku, string ItemName, int WarehouseId, string WarehouseName,
|
||||
int? BatchId, string? BatchNo, DateOnly? ExpiryDate, decimal Qty, int? DaysToExpiry, bool IsExpired);
|
||||
@@ -6,7 +6,11 @@ namespace ERPCore.Dtos.Stock;
|
||||
// Responses (docs/11 §5.4) ------------------------------------------------------
|
||||
|
||||
public sealed record TransferLineDto(
|
||||
int TransferLineId, int ItemId, int? SrcBinId, int? DestBinId, int? BatchId, decimal Qty, decimal QtyReceived);
|
||||
int TransferLineId, int ItemId, int? SrcBinId, int? DestBinId, int? BatchId, decimal Qty, decimal QtyReceived,
|
||||
IReadOnlyList<TransferLineSerialDto> Serials);
|
||||
|
||||
/// <summary>A serial on a transfer line; <see cref="Received"/> once it has arrived.</summary>
|
||||
public sealed record TransferLineSerialDto(int SerialId, string SerialNo, bool Received);
|
||||
|
||||
public sealed record TransferDto(
|
||||
int TransferId, string DocNo, int SrcWarehouseId, int DestWarehouseId, int BranchId,
|
||||
@@ -34,8 +38,11 @@ public sealed class CreateTransferLineInput
|
||||
[Required] public int ItemId { get; set; }
|
||||
public int? SrcBinId { get; set; }
|
||||
public int? DestBinId { get; set; }
|
||||
/// <summary>Batch to move. Omitted for a batch-tracked item, the line is split FEFO across batches.</summary>
|
||||
public int? BatchId { get; set; }
|
||||
[Range(0.0001, double.MaxValue)] public decimal Qty { get; set; }
|
||||
/// <summary>Serials to move — required for a serial-tracked item, one per unit, each InStock at the source.</summary>
|
||||
public List<int>? SerialIds { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateTransferRequest
|
||||
@@ -52,6 +59,11 @@ public sealed class ReceiveTransferLineInput
|
||||
{
|
||||
[Required] public int TransferLineId { get; set; }
|
||||
[Range(0.0001, double.MaxValue)] public decimal Qty { get; set; }
|
||||
/// <summary>
|
||||
/// For a serial line: which in-transit serials arrived (count = Qty). May be omitted when
|
||||
/// receiving everything still outstanding on the line.
|
||||
/// </summary>
|
||||
public List<int>? SerialIds { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ReceiveTransferRequest
|
||||
|
||||
Reference in New Issue
Block a user