df504674e9
CreateJobDto and UpdateJobDto now carry OvenCostId, OvenBatches, and OvenCycleMinutes. The Create POST sets these on the new Job entity and passes them to the pricing engine; the Edit GET populates them from the existing job so the form reflects saved values, and the Edit POST writes them back before repricing. Both Jobs/Create.cshtml and Jobs/Edit.cshtml now include an Oven & Batch Settings card (matching the quote form) with oven selector, batch count, and cycle time inputs. The wizard init block now passes the selected OvenCostId instead of null so live auto-pricing reflects the oven cost. ViewBag.DefaultOvenCycleMinutes added to PopulateCreateEditWizardViewBagsAsync so the placeholder in both views shows the company default. Also fixed: NoExtraLayerCharge was missing from the Edit GET coat DTO mapping (would have caused the flag to reset to false on next edit). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
559 lines
21 KiB
C#
559 lines
21 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using PowderCoating.Application.DTOs.PrepService;
|
|
using PowderCoating.Application.DTOs.Quote;
|
|
|
|
namespace PowderCoating.Application.DTOs.Job;
|
|
|
|
public class JobDto
|
|
{
|
|
public int Id { get; set; }
|
|
public string JobNumber { get; set; } = string.Empty;
|
|
public int CustomerId { get; set; }
|
|
public string CustomerName { get; set; } = string.Empty;
|
|
public string? CustomerCompanyName { get; set; }
|
|
public string? CustomerContactName { get; set; }
|
|
public int? QuoteId { get; set; }
|
|
public string? QuoteNumber { get; set; }
|
|
public string? AssignedUserId { get; set; }
|
|
public string? AssignedWorkerName { get; set; }
|
|
public string Description { get; set; } = string.Empty;
|
|
|
|
// Job Status (from lookup table)
|
|
public int JobStatusId { get; set; }
|
|
public string StatusCode { get; set; } = string.Empty; // For code logic
|
|
public string StatusDisplayName { get; set; } = string.Empty; // For UI
|
|
public string StatusColorClass { get; set; } = "secondary"; // For badges
|
|
public string? StatusIconClass { get; set; } // For icons
|
|
public int StatusDisplayOrder { get; set; } // For comparisons
|
|
public bool StatusIsTerminal { get; set; } // For filtering
|
|
public bool StatusIsWIP { get; set; } // For stats
|
|
|
|
// Job Priority (from lookup table)
|
|
public int JobPriorityId { get; set; }
|
|
public string PriorityCode { get; set; } = string.Empty;
|
|
public string PriorityDisplayName { get; set; } = string.Empty;
|
|
public string PriorityColorClass { get; set; } = "secondary";
|
|
public string? PriorityIconClass { get; set; }
|
|
public int PriorityDisplayOrder { get; set; }
|
|
|
|
public DateTime? ScheduledDate { get; set; }
|
|
public DateTime? DueDate { get; set; }
|
|
public DateTime? CompletedDate { get; set; }
|
|
// Oven selection (carried over from quote)
|
|
public int? OvenCostId { get; set; }
|
|
public string? OvenLabel { get; set; }
|
|
|
|
public decimal QuotedPrice { get; set; }
|
|
public decimal FinalPrice { get; set; }
|
|
public decimal ShopSuppliesAmount { get; set; }
|
|
public decimal ShopSuppliesPercent { get; set; }
|
|
public bool IsRushJob { get; set; }
|
|
public string DiscountType { get; set; } = "None";
|
|
public decimal DiscountValue { get; set; }
|
|
public string? DiscountReason { get; set; }
|
|
public string? CustomerPO { get; set; }
|
|
public string? SpecialInstructions { get; set; }
|
|
public string? InternalNotes { get; set; }
|
|
public string? Tags { get; set; }
|
|
public bool RequiresCustomerApproval { get; set; }
|
|
public bool IsCustomerApproved { get; set; }
|
|
|
|
public string? CustomerEmail { get; set; }
|
|
public bool CustomerNotifyByEmail { get; set; } = true;
|
|
// Customer SMS opt-in — used for SMS compose modal on job details
|
|
public bool CustomerNotifyBySms { get; set; }
|
|
public string? CustomerMobilePhone { get; set; }
|
|
|
|
// Job Completion Details
|
|
public decimal? ActualTimeSpentHours { get; set; }
|
|
|
|
// Part intake / receiving
|
|
public DateTime? IntakeDate { get; set; }
|
|
public string? IntakeConditionNotes { get; set; }
|
|
public int? IntakePartCount { get; set; }
|
|
public string? IntakeCheckedByUserId { get; set; }
|
|
public string? IntakeCheckedByName { get; set; }
|
|
|
|
// Time tracking
|
|
public List<JobTimeEntryDto> TimeEntries { get; set; } = new();
|
|
public decimal TotalLoggedHours => TimeEntries.Sum(t => t.HoursWorked);
|
|
|
|
// Rework
|
|
public bool IsReworkJob { get; set; }
|
|
public int? OriginalJobId { get; set; }
|
|
public string? OriginalJobNumber { get; set; }
|
|
|
|
public List<JobItemDto> Items { get; set; } = new();
|
|
public List<PrepServiceDto> PrepServices { get; set; } = new();
|
|
public List<int> PrepServiceIds { get; set; } = new();
|
|
public DateTime CreatedAt { get; set; }
|
|
}
|
|
|
|
public class JobListDto
|
|
{
|
|
public int Id { get; set; }
|
|
public string JobNumber { get; set; } = string.Empty;
|
|
public string Description { get; set; } = string.Empty;
|
|
public string CustomerName { get; set; } = string.Empty;
|
|
public string? AssignedUserId { get; set; }
|
|
public string? AssignedWorkerName { get; set; }
|
|
|
|
// Job Status (from lookup table)
|
|
public int JobStatusId { get; set; }
|
|
public string StatusCode { get; set; } = string.Empty;
|
|
public string StatusDisplayName { get; set; } = string.Empty;
|
|
public string StatusColorClass { get; set; } = "secondary";
|
|
public bool StatusIsWIP { get; set; }
|
|
|
|
// Job Priority (from lookup table)
|
|
public int JobPriorityId { get; set; }
|
|
public string PriorityCode { get; set; } = string.Empty;
|
|
public string PriorityDisplayName { get; set; } = string.Empty;
|
|
public string PriorityColorClass { get; set; } = "secondary";
|
|
|
|
public string? CustomerEmail { get; set; }
|
|
public bool CustomerNotifyByEmail { get; set; } = true;
|
|
public DateTime? ScheduledDate { get; set; }
|
|
public DateTime? DueDate { get; set; }
|
|
public decimal FinalPrice { get; set; }
|
|
public DateTime CreatedAt { get; set; }
|
|
public string? Tags { get; set; }
|
|
public bool IsReworkJob { get; set; }
|
|
public int? OriginalJobId { get; set; }
|
|
}
|
|
|
|
public class CreateJobDto
|
|
{
|
|
[Required(ErrorMessage = "Customer is required")]
|
|
[Display(Name = "Customer")]
|
|
public int CustomerId { get; set; }
|
|
|
|
[Display(Name = "Quote")]
|
|
public int? QuoteId { get; set; }
|
|
|
|
[Display(Name = "Assigned Worker")]
|
|
public string? AssignedUserId { get; set; }
|
|
|
|
[Display(Name = "Oven")]
|
|
public int? OvenCostId { get; set; }
|
|
|
|
[Display(Name = "Batches")]
|
|
[Range(1, 999)]
|
|
public int OvenBatches { get; set; } = 1;
|
|
|
|
[Display(Name = "Cycle Time (min)")]
|
|
public int? OvenCycleMinutes { get; set; }
|
|
|
|
[Required(ErrorMessage = "Description is required")]
|
|
[StringLength(2000, ErrorMessage = "Description cannot exceed 2000 characters")]
|
|
[Display(Name = "Description")]
|
|
public string Description { get; set; } = string.Empty;
|
|
|
|
[Required(ErrorMessage = "Priority is required")]
|
|
[Display(Name = "Priority")]
|
|
public int JobPriorityId { get; set; } // FK to lookup table
|
|
|
|
[Display(Name = "Scheduled Date")]
|
|
public DateTime? ScheduledDate { get; set; }
|
|
|
|
[Display(Name = "Due Date")]
|
|
public DateTime? DueDate { get; set; }
|
|
|
|
[Range(0, 9999999.99, ErrorMessage = "Quoted price must be between 0 and 9,999,999.99")]
|
|
[Display(Name = "Quoted Price")]
|
|
public decimal QuotedPrice { get; set; }
|
|
|
|
[StringLength(100, ErrorMessage = "Customer PO cannot exceed 100 characters")]
|
|
[Display(Name = "Customer PO")]
|
|
public string? CustomerPO { get; set; }
|
|
|
|
[StringLength(2000, ErrorMessage = "Special instructions cannot exceed 2000 characters")]
|
|
[Display(Name = "Special Instructions")]
|
|
public string? SpecialInstructions { get; set; }
|
|
|
|
[StringLength(2000, ErrorMessage = "Internal notes cannot exceed 2000 characters")]
|
|
[Display(Name = "Internal Notes")]
|
|
public string? InternalNotes { get; set; }
|
|
|
|
[Display(Name = "Tags")]
|
|
[StringLength(500)]
|
|
public string? Tags { get; set; }
|
|
|
|
[Display(Name = "Requires Customer Approval")]
|
|
public bool RequiresCustomerApproval { get; set; }
|
|
|
|
[Display(Name = "Rush Job")]
|
|
public bool IsRushJob { get; set; }
|
|
|
|
[Display(Name = "Discount Type")]
|
|
public string DiscountType { get; set; } = "None";
|
|
|
|
[Range(0, double.MaxValue, ErrorMessage = "Discount value must be 0 or greater")]
|
|
[Display(Name = "Discount Value")]
|
|
public decimal DiscountValue { get; set; }
|
|
|
|
[StringLength(500)]
|
|
[Display(Name = "Discount Reason")]
|
|
public string? DiscountReason { get; set; }
|
|
|
|
public List<CreateQuoteItemDto> JobItems { get; set; } = new();
|
|
public List<int> PrepServiceIds { get; set; } = new();
|
|
}
|
|
|
|
public class UpdateJobDto
|
|
{
|
|
[Required]
|
|
public int Id { get; set; }
|
|
|
|
[Required(ErrorMessage = "Customer is required")]
|
|
[Display(Name = "Customer")]
|
|
public int CustomerId { get; set; }
|
|
|
|
[Display(Name = "Quote")]
|
|
public int? QuoteId { get; set; }
|
|
|
|
[Display(Name = "Assigned Worker")]
|
|
public string? AssignedUserId { get; set; }
|
|
|
|
[Display(Name = "Oven")]
|
|
public int? OvenCostId { get; set; }
|
|
|
|
[Display(Name = "Batches")]
|
|
[Range(1, 999)]
|
|
public int OvenBatches { get; set; } = 1;
|
|
|
|
[Display(Name = "Cycle Time (min)")]
|
|
public int? OvenCycleMinutes { get; set; }
|
|
|
|
[Required(ErrorMessage = "Description is required")]
|
|
[StringLength(2000, ErrorMessage = "Description cannot exceed 2000 characters")]
|
|
[Display(Name = "Description")]
|
|
public string Description { get; set; } = string.Empty;
|
|
|
|
[Required(ErrorMessage = "Status is required")]
|
|
[Display(Name = "Status")]
|
|
public int JobStatusId { get; set; } // FK to lookup table
|
|
|
|
[Required(ErrorMessage = "Priority is required")]
|
|
[Display(Name = "Priority")]
|
|
public int JobPriorityId { get; set; } // FK to lookup table
|
|
|
|
[Display(Name = "Scheduled Date")]
|
|
public DateTime? ScheduledDate { get; set; }
|
|
|
|
[Display(Name = "Due Date")]
|
|
public DateTime? DueDate { get; set; }
|
|
|
|
[Range(0, 9999999.99, ErrorMessage = "Quoted price must be between 0 and 9,999,999.99")]
|
|
[Display(Name = "Quoted Price")]
|
|
public decimal QuotedPrice { get; set; }
|
|
|
|
[StringLength(100, ErrorMessage = "Customer PO cannot exceed 100 characters")]
|
|
[Display(Name = "Customer PO")]
|
|
public string? CustomerPO { get; set; }
|
|
|
|
[StringLength(2000, ErrorMessage = "Special instructions cannot exceed 2000 characters")]
|
|
[Display(Name = "Special Instructions")]
|
|
public string? SpecialInstructions { get; set; }
|
|
|
|
[StringLength(2000, ErrorMessage = "Internal notes cannot exceed 2000 characters")]
|
|
[Display(Name = "Internal Notes")]
|
|
public string? InternalNotes { get; set; }
|
|
|
|
[Display(Name = "Tags")]
|
|
[StringLength(500)]
|
|
public string? Tags { get; set; }
|
|
|
|
[Display(Name = "Requires Customer Approval")]
|
|
public bool RequiresCustomerApproval { get; set; }
|
|
|
|
[Display(Name = "Rush Job")]
|
|
public bool IsRushJob { get; set; }
|
|
|
|
[Display(Name = "Discount Type")]
|
|
public string DiscountType { get; set; } = "None";
|
|
|
|
[Range(0, double.MaxValue, ErrorMessage = "Discount value must be 0 or greater")]
|
|
[Display(Name = "Discount Value")]
|
|
public decimal DiscountValue { get; set; }
|
|
|
|
[StringLength(500)]
|
|
[Display(Name = "Discount Reason")]
|
|
public string? DiscountReason { get; set; }
|
|
|
|
public List<CreateQuoteItemDto> JobItems { get; set; } = new();
|
|
public List<int> PrepServiceIds { get; set; } = new();
|
|
|
|
[Display(Name = "Notify customer of status change via email")]
|
|
public bool SendEmailOnStatusChange { get; set; } = false;
|
|
}
|
|
|
|
public class UpdateJobItemDto
|
|
{
|
|
public int Id { get; set; }
|
|
public string Description { get; set; } = string.Empty;
|
|
public decimal Quantity { get; set; }
|
|
public string? ColorName { get; set; }
|
|
public string? ColorCode { get; set; }
|
|
public decimal? SurfaceArea { get; set; }
|
|
public decimal UnitPrice { get; set; }
|
|
public decimal TotalPrice { get; set; }
|
|
public bool RequiresSandblasting { get; set; }
|
|
public bool RequiresMasking { get; set; }
|
|
public int EstimatedMinutes { get; set; }
|
|
public string? Notes { get; set; }
|
|
}
|
|
|
|
public class JobItemDto
|
|
{
|
|
public int Id { get; set; }
|
|
public string Description { get; set; } = string.Empty;
|
|
public decimal Quantity { get; set; }
|
|
public string? ColorName { get; set; }
|
|
public string? ColorCode { get; set; }
|
|
public string? Finish { get; set; }
|
|
public decimal? SurfaceArea { get; set; }
|
|
public decimal SurfaceAreaSqFt { get; set; }
|
|
public int EstimatedMinutes { get; set; }
|
|
public decimal UnitPrice { get; set; }
|
|
public decimal TotalPrice { get; set; }
|
|
public decimal LaborCost { get; set; }
|
|
public bool RequiresSandblasting { get; set; }
|
|
public bool RequiresMasking { get; set; }
|
|
public string? Notes { get; set; }
|
|
public int? CatalogItemId { get; set; }
|
|
public bool IsGenericItem { get; set; }
|
|
public bool IsLaborItem { get; set; }
|
|
public bool IsSalesItem { get; set; }
|
|
public string? Sku { get; set; }
|
|
public List<JobItemCoatDto> Coats { get; set; } = new();
|
|
public List<JobItemPrepServiceDto> PrepServices { get; set; } = new();
|
|
}
|
|
|
|
public class JobItemPrepServiceDto
|
|
{
|
|
public int PrepServiceId { get; set; }
|
|
public string? PrepServiceName { get; set; }
|
|
public int EstimatedMinutes { get; set; }
|
|
/// <summary>Blast setup selected in wizard for this sandblasting prep service.</summary>
|
|
public int? BlastSetupId { get; set; }
|
|
}
|
|
|
|
public class CreateJobItemDto
|
|
{
|
|
public string Description { get; set; } = string.Empty;
|
|
public decimal Quantity { get; set; }
|
|
public string? ColorName { get; set; }
|
|
public string? ColorCode { get; set; }
|
|
public string? Finish { get; set; }
|
|
public decimal UnitPrice { get; set; }
|
|
public bool RequiresSandblasting { get; set; }
|
|
public bool RequiresMasking { get; set; }
|
|
public int EstimatedMinutes { get; set; }
|
|
public string? Notes { get; set; }
|
|
}
|
|
|
|
// DTO for Shop Floor Display
|
|
public class ShopFloorJobDto
|
|
{
|
|
public int Id { get; set; }
|
|
public string JobNumber { get; set; } = string.Empty;
|
|
public string CustomerName { get; set; } = string.Empty;
|
|
public string Description { get; set; } = string.Empty;
|
|
|
|
// Job Status (from lookup table)
|
|
public int JobStatusId { get; set; }
|
|
public string StatusCode { get; set; } = string.Empty;
|
|
public string StatusDisplayName { get; set; } = string.Empty;
|
|
public string StatusColorClass { get; set; } = "secondary";
|
|
|
|
// Job Priority (from lookup table)
|
|
public int JobPriorityId { get; set; }
|
|
public string PriorityCode { get; set; } = string.Empty;
|
|
public string PriorityDisplayName { get; set; } = string.Empty;
|
|
public string PriorityColorClass { get; set; } = "secondary";
|
|
|
|
public string? AssignedWorkerName { get; set; }
|
|
public DateTime? ScheduledDate { get; set; }
|
|
public DateTime? DueDate { get; set; }
|
|
public int ItemCount { get; set; }
|
|
public List<string> NextSteps { get; set; } = new();
|
|
}
|
|
|
|
// DTO for Job Item Coat (multi-coat support)
|
|
public class JobItemCoatDto
|
|
{
|
|
public int Id { get; set; }
|
|
public int JobItemId { get; set; }
|
|
public string CoatName { get; set; } = string.Empty;
|
|
public int Sequence { get; set; }
|
|
public int? InventoryItemId { get; set; }
|
|
public string? ColorName { get; set; }
|
|
public int? VendorId { get; set; }
|
|
public string? VendorName { get; set; }
|
|
public string? ColorCode { get; set; }
|
|
public string? Finish { get; set; }
|
|
public decimal CoverageSqFtPerLb { get; set; }
|
|
public decimal TransferEfficiency { get; set; }
|
|
public decimal? PowderCostPerLb { get; set; }
|
|
public decimal? PowderToOrder { get; set; }
|
|
public decimal? ActualPowderUsedLbs { get; set; } // Filled during job completion
|
|
public bool NoExtraLayerCharge { get; set; }
|
|
public string? Notes { get; set; }
|
|
}
|
|
|
|
// DTO for completing a job
|
|
public class CompleteJobDto
|
|
{
|
|
public int JobId { get; set; }
|
|
public decimal? ActualTimeSpentHours { get; set; }
|
|
public List<JobPowderUsageDto> PowderUsages { get; set; } = new();
|
|
public bool SendEmailToCustomer { get; set; } = false;
|
|
}
|
|
|
|
// DTO for the Admin/Manager compose-before-send SMS endpoint
|
|
public class SendJobSmsRequest
|
|
{
|
|
public int JobId { get; set; }
|
|
public string Message { get; set; } = string.Empty;
|
|
}
|
|
|
|
// DTO for tracking actual powder usage per inventory item (color) for the whole job
|
|
public class JobPowderUsageDto
|
|
{
|
|
public int InventoryItemId { get; set; }
|
|
public decimal? ActualPowderUsedLbs { get; set; }
|
|
}
|
|
|
|
// ── Time Tracking DTOs ────────────────────────────────────────────────────────
|
|
|
|
public class JobTimeEntryDto
|
|
{
|
|
public int Id { get; set; }
|
|
public int JobId { get; set; }
|
|
public string? UserId { get; set; }
|
|
public string WorkerName { get; set; } = string.Empty;
|
|
public DateTime WorkDate { get; set; }
|
|
public decimal HoursWorked { get; set; }
|
|
public string? Stage { get; set; }
|
|
public string? Notes { get; set; }
|
|
public DateTime CreatedAt { get; set; }
|
|
}
|
|
|
|
public class CreateJobTimeEntryDto
|
|
{
|
|
public int JobId { get; set; }
|
|
public string UserId { get; set; } = string.Empty;
|
|
public DateTime WorkDate { get; set; }
|
|
public decimal HoursWorked { get; set; }
|
|
public string? Stage { get; set; }
|
|
public string? Notes { get; set; }
|
|
}
|
|
|
|
public class UpdateJobTimeEntryDto
|
|
{
|
|
public int Id { get; set; }
|
|
public string UserId { get; set; } = string.Empty;
|
|
public DateTime WorkDate { get; set; }
|
|
public decimal HoursWorked { get; set; }
|
|
public string? Stage { get; set; }
|
|
public string? Notes { get; set; }
|
|
}
|
|
|
|
// ── Rework / Warranty DTOs ────────────────────────────────────────────────────
|
|
|
|
public class ReworkRecordDto
|
|
{
|
|
public int Id { get; set; }
|
|
public int JobId { get; set; }
|
|
public int? JobItemId { get; set; }
|
|
public string? JobItemDescription { get; set; }
|
|
public int? ReworkJobId { get; set; }
|
|
public string? ReworkJobNumber { get; set; }
|
|
|
|
public PowderCoating.Core.Enums.ReworkType ReworkType { get; set; }
|
|
public string ReworkTypeDisplay { get; set; } = string.Empty;
|
|
public PowderCoating.Core.Enums.ReworkReason Reason { get; set; }
|
|
public string ReasonDisplay { get; set; } = string.Empty;
|
|
public string DefectDescription { get; set; } = string.Empty;
|
|
|
|
public PowderCoating.Core.Enums.ReworkDiscoveredBy DiscoveredBy { get; set; }
|
|
public string DiscoveredByDisplay { get; set; } = string.Empty;
|
|
public DateTime DiscoveredDate { get; set; }
|
|
public string? ReportedByName { get; set; }
|
|
|
|
public decimal EstimatedReworkCost { get; set; }
|
|
public decimal ActualReworkCost { get; set; }
|
|
public bool IsBillableToCustomer { get; set; }
|
|
public string? BillingNotes { get; set; }
|
|
|
|
public PowderCoating.Core.Enums.ReworkStatus Status { get; set; }
|
|
public string StatusDisplay { get; set; } = string.Empty;
|
|
public string StatusColorClass { get; set; } = "secondary";
|
|
public PowderCoating.Core.Enums.ReworkResolution? Resolution { get; set; }
|
|
public string? ResolutionDisplay { get; set; }
|
|
public DateTime? ResolvedDate { get; set; }
|
|
public string? ResolutionNotes { get; set; }
|
|
|
|
public DateTime CreatedAt { get; set; }
|
|
}
|
|
|
|
public class CreateReworkRecordDto
|
|
{
|
|
public int JobId { get; set; }
|
|
public int? JobItemId { get; set; }
|
|
public PowderCoating.Core.Enums.ReworkType ReworkType { get; set; }
|
|
public PowderCoating.Core.Enums.ReworkReason Reason { get; set; }
|
|
public string DefectDescription { get; set; } = string.Empty;
|
|
public PowderCoating.Core.Enums.ReworkDiscoveredBy DiscoveredBy { get; set; }
|
|
public DateTime DiscoveredDate { get; set; } = DateTime.Today;
|
|
public string? ReportedByName { get; set; }
|
|
public decimal EstimatedReworkCost { get; set; }
|
|
public bool IsBillableToCustomer { get; set; }
|
|
public string? BillingNotes { get; set; }
|
|
}
|
|
|
|
public class UpdateReworkRecordDto
|
|
{
|
|
public int Id { get; set; }
|
|
public PowderCoating.Core.Enums.ReworkStatus Status { get; set; }
|
|
public PowderCoating.Core.Enums.ReworkResolution? Resolution { get; set; }
|
|
public decimal ActualReworkCost { get; set; }
|
|
public bool IsBillableToCustomer { get; set; }
|
|
public string? BillingNotes { get; set; }
|
|
public DateTime? ResolvedDate { get; set; }
|
|
public string? ResolutionNotes { get; set; }
|
|
public int? ReworkJobId { get; set; }
|
|
}
|
|
|
|
// ViewModel for the Edit Items wizard page
|
|
public class JobEditItemsViewModel
|
|
{
|
|
public int JobId { get; set; }
|
|
public string JobNumber { get; set; } = string.Empty;
|
|
public int? CustomerId { get; set; }
|
|
public decimal TaxPercent { get; set; }
|
|
public int? OvenCostId { get; set; }
|
|
public int OvenBatches { get; set; } = 1;
|
|
public int? OvenCycleMinutes { get; set; }
|
|
public List<CreateQuoteItemDto> JobItems { get; set; } = new();
|
|
}
|
|
|
|
// DTO for the part intake / receiving form
|
|
public class IntakeJobDto
|
|
{
|
|
[Required]
|
|
public int JobId { get; set; }
|
|
|
|
[Display(Name = "Actual Part Count")]
|
|
[Range(0, 10000, ErrorMessage = "Part count must be between 0 and 10,000")]
|
|
public int? ActualPartCount { get; set; }
|
|
|
|
[StringLength(2000, ErrorMessage = "Condition notes cannot exceed 2000 characters")]
|
|
[Display(Name = "Condition Notes")]
|
|
public string? ConditionNotes { get; set; }
|
|
|
|
[Display(Name = "Advance status to In Preparation")]
|
|
public bool AdvanceToInPreparation { get; set; } = true;
|
|
}
|