1a44133a63
Removes the ShopWorker and ShopWorkerRoleCost entities, all related DTOs, mappings, controllers, views, and import/export paths. Worker identity is now handled entirely through ApplicationUser with per-user LaborCostPerHour. ShopWorkerRoleCosts table remains in production pending manual data migration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
248 lines
15 KiB
C#
248 lines
15 KiB
C#
using AutoMapper;
|
|
using PowderCoating.Core.Entities;
|
|
using PowderCoating.Core.Enums;
|
|
using PowderCoating.Application.DTOs.Job;
|
|
|
|
namespace PowderCoating.Application.Mappings;
|
|
|
|
public class JobProfile : Profile
|
|
{
|
|
public JobProfile()
|
|
{
|
|
// Job to JobDto - Map all lookup properties from navigation
|
|
CreateMap<Job, JobDto>()
|
|
.ForMember(dest => dest.CustomerName,
|
|
opt => opt.MapFrom(src => src.Customer != null
|
|
? (!string.IsNullOrWhiteSpace(src.Customer.CompanyName)
|
|
? src.Customer.CompanyName
|
|
: $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim())
|
|
: string.Empty))
|
|
.ForMember(dest => dest.CustomerCompanyName,
|
|
opt => opt.MapFrom(src => src.Customer != null ? src.Customer.CompanyName : null))
|
|
.ForMember(dest => dest.CustomerContactName,
|
|
opt => opt.MapFrom(src => src.Customer != null
|
|
? $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim()
|
|
: null))
|
|
.ForMember(dest => dest.AssignedWorkerName,
|
|
opt => opt.MapFrom(src => src.AssignedUser != null ? src.AssignedUser.FullName : null))
|
|
// Status lookup mappings
|
|
.ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId))
|
|
.ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.JobStatus.StatusCode))
|
|
.ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.JobStatus.DisplayName))
|
|
.ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.JobStatus.ColorClass))
|
|
.ForMember(dest => dest.StatusIconClass, opt => opt.MapFrom(src => src.JobStatus.IconClass))
|
|
.ForMember(dest => dest.StatusDisplayOrder, opt => opt.MapFrom(src => src.JobStatus.DisplayOrder))
|
|
.ForMember(dest => dest.StatusIsTerminal, opt => opt.MapFrom(src => src.JobStatus.IsTerminalStatus))
|
|
.ForMember(dest => dest.StatusIsWIP, opt => opt.MapFrom(src => src.JobStatus.IsWorkInProgressStatus))
|
|
// Priority lookup mappings
|
|
.ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId))
|
|
.ForMember(dest => dest.PriorityCode, opt => opt.MapFrom(src => src.JobPriority.PriorityCode))
|
|
.ForMember(dest => dest.PriorityDisplayName, opt => opt.MapFrom(src => src.JobPriority.DisplayName))
|
|
.ForMember(dest => dest.PriorityColorClass, opt => opt.MapFrom(src => src.JobPriority.ColorClass))
|
|
.ForMember(dest => dest.PriorityIconClass, opt => opt.MapFrom(src => src.JobPriority.IconClass))
|
|
.ForMember(dest => dest.PriorityDisplayOrder, opt => opt.MapFrom(src => src.JobPriority.DisplayOrder))
|
|
// Oven selection
|
|
.ForMember(dest => dest.OvenLabel,
|
|
opt => opt.MapFrom(src => src.OvenCost != null ? src.OvenCost.Label : null))
|
|
.ForMember(dest => dest.Items,
|
|
opt => opt.MapFrom(src => src.JobItems))
|
|
// Prep services mappings
|
|
.ForMember(dest => dest.PrepServices, opt => opt.MapFrom(src =>
|
|
src.JobPrepServices.Select(jps => jps.PrepService).ToList()))
|
|
.ForMember(dest => dest.PrepServiceIds, opt => opt.MapFrom(src =>
|
|
src.JobPrepServices.Select(jps => jps.PrepServiceId).ToList()))
|
|
.ForMember(dest => dest.TimeEntries, opt => opt.MapFrom(src => src.TimeEntries))
|
|
.ForMember(dest => dest.DiscountType, opt => opt.MapFrom(src => src.DiscountType.ToString()))
|
|
.ForMember(dest => dest.IsReworkJob, opt => opt.MapFrom(src => src.IsReworkJob))
|
|
.ForMember(dest => dest.OriginalJobId, opt => opt.MapFrom(src => src.OriginalJobId))
|
|
.ForMember(dest => dest.OriginalJobNumber,
|
|
opt => opt.MapFrom(src => src.OriginalJob != null ? src.OriginalJob.JobNumber : null))
|
|
.ForMember(dest => dest.IntakeCheckedByName,
|
|
opt => opt.MapFrom(src => src.IntakeCheckedBy != null ? src.IntakeCheckedBy.FullName : null))
|
|
.ForMember(dest => dest.CustomerEmail,
|
|
opt => opt.MapFrom(src => src.Customer != null ? src.Customer.Email : null))
|
|
.ForMember(dest => dest.CustomerNotifyByEmail,
|
|
opt => opt.MapFrom(src => src.Customer == null || src.Customer.NotifyByEmail))
|
|
.ForMember(dest => dest.CustomerNotifyBySms,
|
|
opt => opt.MapFrom(src => src.Customer != null && src.Customer.NotifyBySms))
|
|
.ForMember(dest => dest.CustomerMobilePhone,
|
|
opt => opt.MapFrom(src => src.Customer != null
|
|
? (src.Customer.MobilePhone ?? src.Customer.Phone)
|
|
: null));
|
|
|
|
// JobTimeEntry → JobTimeEntryDto
|
|
CreateMap<JobTimeEntry, JobTimeEntryDto>()
|
|
.ForMember(dest => dest.WorkerName, opt => opt.MapFrom(src =>
|
|
src.UserDisplayName ?? string.Empty));
|
|
|
|
// CreateJobDto to Job
|
|
CreateMap<CreateJobDto, Job>()
|
|
.ForMember(dest => dest.JobNumber, opt => opt.Ignore()) // Generated by system
|
|
.ForMember(dest => dest.JobStatus, opt => opt.Ignore()) // Will be set by FK
|
|
.ForMember(dest => dest.JobPriority, opt => opt.Ignore()) // Will be set by FK
|
|
.ForMember(dest => dest.OvenCost, opt => opt.Ignore()) // Will be set by FK
|
|
.ForMember(dest => dest.JobPrepServices, opt => opt.Ignore()) // Handled separately
|
|
.ForMember(dest => dest.JobItems, opt => opt.Ignore()); // Handled separately
|
|
|
|
// UpdateJobDto to Job
|
|
CreateMap<UpdateJobDto, Job>()
|
|
.ForMember(dest => dest.JobNumber, opt => opt.Ignore()) // Cannot be changed
|
|
.ForMember(dest => dest.JobStatus, opt => opt.Ignore()) // Will be set by FK
|
|
.ForMember(dest => dest.JobPriority, opt => opt.Ignore()) // Will be set by FK
|
|
.ForMember(dest => dest.OvenCost, opt => opt.Ignore()) // Will be set by FK
|
|
.ForMember(dest => dest.JobPrepServices, opt => opt.Ignore()) // Handled separately
|
|
.ForMember(dest => dest.JobItems, opt => opt.Ignore()); // Handled separately
|
|
|
|
// Job to UpdateJobDto (needed for Edit GET action)
|
|
CreateMap<Job, UpdateJobDto>()
|
|
.ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId))
|
|
.ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId))
|
|
.ForMember(dest => dest.PrepServiceIds, opt => opt.MapFrom(src =>
|
|
src.JobPrepServices.Select(jps => jps.PrepServiceId).ToList()));
|
|
|
|
// Job to JobListDto
|
|
CreateMap<Job, JobListDto>()
|
|
.ForMember(dest => dest.CustomerName,
|
|
opt => opt.MapFrom(src => src.Customer != null
|
|
? (!string.IsNullOrWhiteSpace(src.Customer.CompanyName)
|
|
? src.Customer.CompanyName
|
|
: $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim())
|
|
: string.Empty))
|
|
.ForMember(dest => dest.AssignedWorkerName,
|
|
opt => opt.MapFrom(src => src.AssignedUser != null ? src.AssignedUser.FullName : null))
|
|
// Status lookup mappings
|
|
.ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId))
|
|
.ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.JobStatus.StatusCode))
|
|
.ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.JobStatus.DisplayName))
|
|
.ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.JobStatus.ColorClass))
|
|
.ForMember(dest => dest.StatusIsWIP, opt => opt.MapFrom(src => src.JobStatus.IsWorkInProgressStatus))
|
|
// Priority lookup mappings
|
|
.ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId))
|
|
.ForMember(dest => dest.PriorityCode, opt => opt.MapFrom(src => src.JobPriority.PriorityCode))
|
|
.ForMember(dest => dest.PriorityDisplayName, opt => opt.MapFrom(src => src.JobPriority.DisplayName))
|
|
.ForMember(dest => dest.PriorityColorClass, opt => opt.MapFrom(src => src.JobPriority.ColorClass))
|
|
.ForMember(dest => dest.CustomerEmail,
|
|
opt => opt.MapFrom(src => src.Customer != null ? src.Customer.Email : null))
|
|
.ForMember(dest => dest.CustomerNotifyByEmail,
|
|
opt => opt.MapFrom(src => src.Customer == null || src.Customer.NotifyByEmail));
|
|
|
|
// JobItem mappings
|
|
CreateMap<JobItem, JobItemDto>()
|
|
.ForMember(dest => dest.Coats, opt => opt.MapFrom(src => src.Coats))
|
|
.ForMember(dest => dest.PrepServices, opt => opt.MapFrom(src => src.PrepServices));
|
|
|
|
CreateMap<JobItemPrepService, JobItemPrepServiceDto>()
|
|
.ForMember(dest => dest.PrepServiceName,
|
|
opt => opt.MapFrom(src => src.PrepService != null ? src.PrepService.ServiceName : null));
|
|
CreateMap<CreateJobItemDto, JobItem>()
|
|
.ForMember(dest => dest.TotalPrice,
|
|
opt => opt.MapFrom(src => src.UnitPrice * src.Quantity));
|
|
CreateMap<UpdateJobItemDto, JobItem>();
|
|
CreateMap<JobItem, UpdateJobItemDto>();
|
|
|
|
// JobItemCoat mappings
|
|
CreateMap<JobItemCoat, JobItemCoatDto>()
|
|
.ForMember(dest => dest.VendorName,
|
|
opt => opt.MapFrom(src => src.Vendor != null ? src.Vendor.CompanyName : null));
|
|
|
|
// Job to ShopFloorJobDto
|
|
CreateMap<Job, ShopFloorJobDto>()
|
|
.ForMember(dest => dest.CustomerName,
|
|
opt => opt.MapFrom(src => src.Customer != null
|
|
? (!string.IsNullOrWhiteSpace(src.Customer.CompanyName)
|
|
? src.Customer.CompanyName
|
|
: $"{src.Customer.ContactFirstName} {src.Customer.ContactLastName}".Trim())
|
|
: string.Empty))
|
|
.ForMember(dest => dest.AssignedWorkerName,
|
|
opt => opt.MapFrom(src => src.AssignedUser != null ? src.AssignedUser.FullName : null))
|
|
// Status lookup mappings
|
|
.ForMember(dest => dest.JobStatusId, opt => opt.MapFrom(src => src.JobStatusId))
|
|
.ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.JobStatus.StatusCode))
|
|
.ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.JobStatus.DisplayName))
|
|
.ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.JobStatus.ColorClass))
|
|
// Priority lookup mappings
|
|
.ForMember(dest => dest.JobPriorityId, opt => opt.MapFrom(src => src.JobPriorityId))
|
|
.ForMember(dest => dest.PriorityCode, opt => opt.MapFrom(src => src.JobPriority.PriorityCode))
|
|
.ForMember(dest => dest.PriorityDisplayName, opt => opt.MapFrom(src => src.JobPriority.DisplayName))
|
|
.ForMember(dest => dest.PriorityColorClass, opt => opt.MapFrom(src => src.JobPriority.ColorClass))
|
|
.ForMember(dest => dest.ItemCount,
|
|
opt => opt.MapFrom(src => src.JobItems.Count));
|
|
// Note: NextSteps will be removed - was workflow logic that will be reimplemented later
|
|
|
|
// JobPhoto mappings
|
|
CreateMap<JobPhoto, JobPhotoDto>()
|
|
.ForMember(dest => dest.PhotoTypeDisplay,
|
|
opt => opt.MapFrom(src => FormatEnumName(src.PhotoType.ToString())))
|
|
.ForMember(dest => dest.UploadedByName,
|
|
opt => opt.MapFrom(src => src.UploadedBy != null ? src.UploadedBy.FullName : "Unknown"));
|
|
|
|
CreateMap<UploadJobPhotoDto, JobPhoto>();
|
|
CreateMap<UpdateJobPhotoDto, JobPhoto>();
|
|
|
|
// ReworkRecord → ReworkRecordDto
|
|
CreateMap<ReworkRecord, ReworkRecordDto>()
|
|
.ForMember(dest => dest.ReworkTypeDisplay,
|
|
opt => opt.MapFrom(src => FormatEnumName(src.ReworkType.ToString())))
|
|
.ForMember(dest => dest.ReasonDisplay,
|
|
opt => opt.MapFrom(src => FormatReworkReason(src.Reason)))
|
|
.ForMember(dest => dest.DiscoveredByDisplay,
|
|
opt => opt.MapFrom(src => src.DiscoveredBy == ReworkDiscoveredBy.Internal ? "Internal (QC)" : "Customer"))
|
|
.ForMember(dest => dest.StatusDisplay,
|
|
opt => opt.MapFrom(src => FormatEnumName(src.Status.ToString())))
|
|
.ForMember(dest => dest.StatusColorClass,
|
|
opt => opt.MapFrom(src => GetReworkStatusColor(src.Status)))
|
|
.ForMember(dest => dest.ResolutionDisplay,
|
|
opt => opt.MapFrom(src => src.Resolution.HasValue ? FormatReworkResolution(src.Resolution.Value) : null))
|
|
.ForMember(dest => dest.JobItemDescription,
|
|
opt => opt.MapFrom(src => src.JobItem != null ? src.JobItem.Description : null))
|
|
.ForMember(dest => dest.ReworkJobNumber,
|
|
opt => opt.MapFrom(src => src.ReworkJob != null ? src.ReworkJob.JobNumber : null));
|
|
|
|
// Job → JobDto (rework fields)
|
|
// (IsReworkJob and OriginalJobId map by convention; OriginalJobNumber needs explicit map — handled in controller)
|
|
|
|
// Job → JobListDto (rework fields map by convention)
|
|
|
|
// JobChangeHistory -> JobChangeHistoryDto
|
|
CreateMap<JobChangeHistory, JobChangeHistoryDto>()
|
|
.ForMember(dest => dest.ChangedByName, opt => opt.MapFrom(src =>
|
|
src.ChangedBy != null ? $"{src.ChangedBy.FirstName} {src.ChangedBy.LastName}" : "Unknown"));
|
|
}
|
|
|
|
private static string FormatEnumName(string enumName) =>
|
|
System.Text.RegularExpressions.Regex.Replace(enumName, "([a-z])([A-Z])", "$1 $2");
|
|
|
|
private static string FormatReworkReason(ReworkReason reason) => reason switch
|
|
{
|
|
ReworkReason.AdhesionFailure => "Adhesion Failure",
|
|
ReworkReason.Contamination => "Contamination",
|
|
ReworkReason.ColorMismatch => "Color Mismatch",
|
|
ReworkReason.RunsSags => "Runs / Sags",
|
|
ReworkReason.SurfacePrepFailure => "Surface Prep Failure",
|
|
ReworkReason.OvenIssue => "Oven Issue",
|
|
ReworkReason.InsufficientCoverage => "Insufficient Coverage",
|
|
ReworkReason.HandlingDamage => "Handling Damage",
|
|
_ => "Other"
|
|
};
|
|
|
|
private static string FormatReworkResolution(ReworkResolution resolution) => resolution switch
|
|
{
|
|
ReworkResolution.RecoatedNoCharge => "Recoated — No Charge",
|
|
ReworkResolution.RecoatedBilled => "Recoated — Billed to Customer",
|
|
ReworkResolution.CustomerCredited => "Customer Credited",
|
|
ReworkResolution.WrittenOff => "Written Off",
|
|
ReworkResolution.NoActionRequired => "No Action Required",
|
|
_ => resolution.ToString()
|
|
};
|
|
|
|
private static string GetReworkStatusColor(ReworkStatus status) => status switch
|
|
{
|
|
ReworkStatus.Open => "danger",
|
|
ReworkStatus.InProgress => "warning",
|
|
ReworkStatus.Resolved => "success",
|
|
ReworkStatus.WrittenOff => "secondary",
|
|
ReworkStatus.Disputed => "info",
|
|
_ => "secondary"
|
|
};
|
|
}
|