feat: Implement procurement services and number sequence management
- Added INumberSequenceService interface for generating document numbers. - Created NumberSequenceService to handle atomic document number issuance. - Introduced IPurchaseOrderService interface and implemented PurchaseOrderService for managing purchase orders. - Added IRequisitionService interface and implemented RequisitionService for handling requisitions. - Created IRfqService interface and implemented RfqService for managing RFQs and vendor quotations. - Defined necessary DTOs and domain entities for procurement processes. - Ensured proper validation and error handling across services.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ERPCore.Domain.Enums;
|
||||
|
||||
namespace ERPCore.Dtos.Procurement;
|
||||
|
||||
// Responses (docs/11 §3.3) ------------------------------------------------------
|
||||
|
||||
public sealed record PoLineDto(
|
||||
long PoLineId, long ItemId, long UomId, long WarehouseId,
|
||||
decimal Qty, decimal UnitPrice, decimal Tax, decimal QtyReceived);
|
||||
|
||||
public sealed record PoTotalsDto(decimal SubTotal, decimal Tax, decimal GrandTotal, string Currency);
|
||||
|
||||
public sealed record PurchaseOrderDto(
|
||||
long PoId, string DocNo, long VendorId, long? RequisitionId, PurchaseOrderStatus Status,
|
||||
bool ApprovalRequired, long CreatedBy, DateTime CreatedAt, DateTime? UpdatedAt,
|
||||
PoTotalsDto Totals, IReadOnlyList<PoLineDto> Lines);
|
||||
|
||||
public sealed record PurchaseOrderSummaryDto(
|
||||
long PoId, string DocNo, long VendorId, PurchaseOrderStatus Status,
|
||||
bool ApprovalRequired, DateTime CreatedAt, PoTotalsDto Totals);
|
||||
|
||||
// Requests — server sets docNo, status, createdBy, timestamps, qtyReceived, totals
|
||||
|
||||
public sealed class CreatePoLineInput
|
||||
{
|
||||
[Required] public long ItemId { get; set; }
|
||||
[Required] public long UomId { get; set; }
|
||||
[Required] public long WarehouseId { get; set; }
|
||||
[Range(0.0001, double.MaxValue)] public decimal Qty { get; set; }
|
||||
[Range(0, double.MaxValue)] public decimal UnitPrice { get; set; }
|
||||
[Range(0, 1)] public decimal Tax { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreatePurchaseOrderRequest
|
||||
{
|
||||
[Required] public long VendorId { get; set; }
|
||||
public long? RequisitionId { get; set; }
|
||||
[Required, MinLength(1)] public List<CreatePoLineInput> Lines { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class UpdatePurchaseOrderRequest
|
||||
{
|
||||
[Required] public long VendorId { get; set; }
|
||||
public long? RequisitionId { get; set; }
|
||||
[Required, MinLength(1)] public List<CreatePoLineInput> Lines { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class CancelPurchaseOrderRequest
|
||||
{
|
||||
[StringLength(500)] public string? Reason { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ERPCore.Domain.Enums;
|
||||
|
||||
namespace ERPCore.Dtos.Procurement;
|
||||
|
||||
// Responses (docs/11 §3.1) ------------------------------------------------------
|
||||
|
||||
public sealed record RequisitionLineDto(long ReqLineId, long ItemId, decimal Qty, DateOnly? RequiredBy);
|
||||
|
||||
public sealed record RequisitionDto(
|
||||
long RequisitionId, string DocNo, RequisitionStatus Status, long RequestedBy,
|
||||
DateTime CreatedAt, IReadOnlyList<RequisitionLineDto> Lines);
|
||||
|
||||
public sealed record RequisitionSummaryDto(
|
||||
long RequisitionId, string DocNo, RequisitionStatus Status, long RequestedBy, DateTime CreatedAt);
|
||||
|
||||
// Requests — server sets docNo, status, requestedBy (audit actor), timestamps ----
|
||||
|
||||
public sealed class CreateRequisitionLineInput
|
||||
{
|
||||
[Required] public long ItemId { get; set; }
|
||||
[Range(0.0001, double.MaxValue)] public decimal Qty { get; set; }
|
||||
public DateOnly? RequiredBy { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateRequisitionRequest
|
||||
{
|
||||
[Required, MinLength(1)] public List<CreateRequisitionLineInput> Lines { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ERPCore.Domain.Enums;
|
||||
|
||||
namespace ERPCore.Dtos.Procurement;
|
||||
|
||||
// Responses (docs/11 §3.2) ------------------------------------------------------
|
||||
|
||||
public sealed record RfqLineDto(long RfqLineId, long ItemId, decimal Qty);
|
||||
|
||||
public sealed record RfqDto(
|
||||
long RfqId, string DocNo, long RequisitionId, RfqStatus Status, IReadOnlyList<RfqLineDto> Lines);
|
||||
|
||||
public sealed record QuotationLineDto(long ItemId, decimal UnitPrice, int LeadDays);
|
||||
|
||||
public sealed record VendorQuotationDto(
|
||||
long QuotationId, long RfqId, long VendorId, IReadOnlyList<QuotationLineDto> Lines);
|
||||
|
||||
/// <summary>Per-item, per-vendor price matrix for <c>GET /rfqs/{id}/comparison</c>.</summary>
|
||||
public sealed record RfqComparisonCellDto(long VendorId, long QuotationId, decimal UnitPrice, int LeadDays);
|
||||
public sealed record RfqComparisonRowDto(long ItemId, decimal Qty, IReadOnlyList<RfqComparisonCellDto> Quotes);
|
||||
public sealed record RfqComparisonDto(long RfqId, IReadOnlyList<long> VendorIds, IReadOnlyList<RfqComparisonRowDto> Rows);
|
||||
|
||||
// Requests ----------------------------------------------------------------------
|
||||
|
||||
public sealed class CreateRfqLineInput
|
||||
{
|
||||
[Required] public long ItemId { get; set; }
|
||||
[Range(0.0001, double.MaxValue)] public decimal Qty { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateRfqRequest
|
||||
{
|
||||
[Required] public long RequisitionId { get; set; }
|
||||
/// <summary>Vendors the RFQ is issued to (validated for existence; quotations reference them).</summary>
|
||||
public List<long> VendorIds { get; set; } = new();
|
||||
[Required, MinLength(1)] public List<CreateRfqLineInput> Lines { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class CreateQuotationLineInput
|
||||
{
|
||||
[Required] public long ItemId { get; set; }
|
||||
[Range(0, double.MaxValue)] public decimal UnitPrice { get; set; }
|
||||
[Range(0, int.MaxValue)] public int LeadDays { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CreateQuotationRequest
|
||||
{
|
||||
[Required] public long VendorId { get; set; }
|
||||
[Required, MinLength(1)] public List<CreateQuotationLineInput> Lines { get; set; } = new();
|
||||
}
|
||||
Reference in New Issue
Block a user