using System.ComponentModel.DataAnnotations; using PowderCoating.Core.Enums; namespace PowderCoating.Application.DTOs.PurchaseOrder; // ============================================================================ // LIST / SUMMARY // ============================================================================ public class PurchaseOrderListDto { public int Id { get; set; } public string PoNumber { get; set; } = string.Empty; public int VendorId { get; set; } public string VendorName { get; set; } = string.Empty; public PurchaseOrderStatus Status { get; set; } public DateTime OrderDate { get; set; } public DateTime? ExpectedDeliveryDate { get; set; } public DateTime? ReceivedDate { get; set; } public decimal ShippingCost { get; set; } public decimal SubTotal { get; set; } public decimal TotalAmount { get; set; } public int ItemCount { get; set; } public bool IsOverdue => Status is PurchaseOrderStatus.Draft or PurchaseOrderStatus.Submitted or PurchaseOrderStatus.PartiallyReceived && ExpectedDeliveryDate.HasValue && ExpectedDeliveryDate.Value.Date < DateTime.UtcNow.Date; } // ============================================================================ // DETAILS // ============================================================================ public class PurchaseOrderDto { public int Id { get; set; } public string PoNumber { get; set; } = string.Empty; public int VendorId { get; set; } public string VendorName { get; set; } = string.Empty; public string? VendorEmail { get; set; } public string? VendorPhone { get; set; } public PurchaseOrderStatus Status { get; set; } public DateTime OrderDate { get; set; } public DateTime? ExpectedDeliveryDate { get; set; } public DateTime? ReceivedDate { get; set; } public decimal ShippingCost { get; set; } public decimal SubTotal { get; set; } public decimal TotalAmount { get; set; } public string? Notes { get; set; } public string? InternalNotes { get; set; } public int? BillId { get; set; } public string? BillNumber { get; set; } public List Items { get; set; } = new(); public bool IsOverdue => Status is PurchaseOrderStatus.Draft or PurchaseOrderStatus.Submitted or PurchaseOrderStatus.PartiallyReceived && ExpectedDeliveryDate.HasValue && ExpectedDeliveryDate.Value.Date < DateTime.UtcNow.Date; } // ============================================================================ // CREATE / UPDATE // ============================================================================ public class CreatePurchaseOrderDto { [Required] public int VendorId { get; set; } [Required] [Display(Name = "Order Date")] public DateTime OrderDate { get; set; } = DateTime.Today; [Display(Name = "Expected Delivery")] public DateTime? ExpectedDeliveryDate { get; set; } [Display(Name = "Shipping Cost")] [Range(0, 999999)] public decimal ShippingCost { get; set; } = 0; [Display(Name = "Notes")] [StringLength(1000)] public string? Notes { get; set; } [Display(Name = "Internal Notes")] [StringLength(1000)] public string? InternalNotes { get; set; } public List Items { get; set; } = new(); } public class UpdatePurchaseOrderDto { [Required] public int VendorId { get; set; } [Required] [Display(Name = "Order Date")] public DateTime OrderDate { get; set; } = DateTime.Today; [Display(Name = "Expected Delivery")] public DateTime? ExpectedDeliveryDate { get; set; } [Display(Name = "Shipping Cost")] [Range(0, 999999)] public decimal ShippingCost { get; set; } = 0; [Display(Name = "Notes")] [StringLength(1000)] public string? Notes { get; set; } [Display(Name = "Internal Notes")] [StringLength(1000)] public string? InternalNotes { get; set; } public List Items { get; set; } = new(); } // ============================================================================ // LINE ITEMS // ============================================================================ public class PurchaseOrderItemDto { public int Id { get; set; } public int PurchaseOrderId { get; set; } public int? InventoryItemId { get; set; } public string ItemName { get; set; } = string.Empty; // Inventory item name OR custom description public string ItemSKU { get; set; } = string.Empty; public string UnitOfMeasure { get; set; } = string.Empty; public bool IsCustomItem => InventoryItemId == null; public decimal QuantityOrdered { get; set; } public decimal QuantityReceived { get; set; } public decimal UnitCost { get; set; } public decimal LineTotal { get; set; } public string? Notes { get; set; } public bool IsFullyReceived => QuantityReceived >= QuantityOrdered; public decimal QuantityRemaining => Math.Max(0, QuantityOrdered - QuantityReceived); } public class CreatePurchaseOrderItemDto { // Null = custom/non-inventory line item public int? InventoryItemId { get; set; } // Required when InventoryItemId is null [StringLength(200)] public string? Description { get; set; } [StringLength(50)] public string? UnitOfMeasure { get; set; } [Required] [Range(0.001, 999999, ErrorMessage = "Quantity must be greater than 0")] public decimal QuantityOrdered { get; set; } [Required] [Range(0, 999999)] public decimal UnitCost { get; set; } [StringLength(500)] public string? Notes { get; set; } } // ============================================================================ // RECEIVING // ============================================================================ public class ReceivePurchaseOrderDto { [Required] [Display(Name = "Received Date")] public DateTime ReceivedDate { get; set; } = DateTime.Today; [StringLength(500)] public string? Notes { get; set; } public List Items { get; set; } = new(); } public class ReceiveItemDto { public int PurchaseOrderItemId { get; set; } public int? InventoryItemId { get; set; } public string ItemName { get; set; } = string.Empty; public string ItemSKU { get; set; } = string.Empty; public string UnitOfMeasure { get; set; } = string.Empty; public decimal QuantityOrdered { get; set; } public decimal QuantityAlreadyReceived { get; set; } public decimal QuantityRemaining { get; set; } [Range(0, 999999)] public decimal QuantityToReceive { get; set; } }