using AutoMapper; using PowderCoating.Application.DTOs.Quote; using PowderCoating.Core.Entities; namespace PowderCoating.Application.Mappings; public class QuoteProfile : Profile { public QuoteProfile() { // ============================================================================ // Quote Entity <-> DTOs // ============================================================================ // Quote -> QuoteListDto CreateMap() .ForMember(dest => dest.CustomerOrProspectName, opt => opt.MapFrom(src => src.Customer != null ? (!string.IsNullOrWhiteSpace(src.Customer.CompanyName) ? src.Customer.CompanyName : (src.Customer.ContactFirstName + " " + src.Customer.ContactLastName).Trim()) : src.ProspectCompanyName ?? src.ProspectContactName ?? "Unknown")) .ForMember(dest => dest.IsProspect, opt => opt.MapFrom(src => !src.CustomerId.HasValue)) // Status lookup mappings .ForMember(dest => dest.QuoteStatusId, opt => opt.MapFrom(src => src.QuoteStatusId)) .ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.QuoteStatus.StatusCode)) .ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.QuoteStatus.DisplayName)) .ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.QuoteStatus.ColorClass)) .ForMember(dest => dest.StatusIsDraft, opt => opt.MapFrom(src => src.QuoteStatus.IsDraftStatus)); // Quote -> QuoteDto CreateMap() .ForMember(dest => dest.OvenLabel, opt => opt.MapFrom(src => src.OvenCost != null ? src.OvenCost.Label : null)) .ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer != null ? src.Customer.CompanyName : null)) .ForMember(dest => dest.CustomerEmail, opt => opt.MapFrom(src => src.Customer != null ? src.Customer.Email : src.ProspectEmail)) .ForMember(dest => dest.CustomerMobilePhone, opt => opt.MapFrom(src => src.Customer != null ? src.Customer.MobilePhone : null)) .ForMember(dest => dest.CustomerNotifyBySms, opt => opt.MapFrom(src => src.Customer != null && src.Customer.NotifyBySms)) .ForMember(dest => dest.CustomerNotifyByEmail, opt => opt.MapFrom(src => src.Customer == null || src.Customer.NotifyByEmail)) .ForMember(dest => dest.PreparedByName, opt => opt.MapFrom(src => src.PreparedBy != null ? $"{src.PreparedBy.FirstName} {src.PreparedBy.LastName}" : null)) // Discount enum to string conversion .ForMember(dest => dest.DiscountType, opt => opt.MapFrom(src => src.DiscountType.ToString())) // Status lookup mappings .ForMember(dest => dest.QuoteStatusId, opt => opt.MapFrom(src => src.QuoteStatusId)) .ForMember(dest => dest.StatusCode, opt => opt.MapFrom(src => src.QuoteStatus.StatusCode)) .ForMember(dest => dest.StatusDisplayName, opt => opt.MapFrom(src => src.QuoteStatus.DisplayName)) .ForMember(dest => dest.StatusColorClass, opt => opt.MapFrom(src => src.QuoteStatus.ColorClass)) .ForMember(dest => dest.StatusIconClass, opt => opt.MapFrom(src => src.QuoteStatus.IconClass)) .ForMember(dest => dest.StatusIsApproved, opt => opt.MapFrom(src => src.QuoteStatus.IsApprovedStatus)) .ForMember(dest => dest.StatusIsConverted, opt => opt.MapFrom(src => src.QuoteStatus.IsConvertedStatus)) .ForMember(dest => dest.StatusIsDraft, opt => opt.MapFrom(src => src.QuoteStatus.IsDraftStatus)) // Prep Services mappings .ForMember(dest => dest.PrepServices, opt => opt.MapFrom(src => src.QuotePrepServices.Select(qps => qps.PrepService).ToList())) .ForMember(dest => dest.PrepServiceIds, opt => opt.MapFrom(src => src.QuotePrepServices.Select(qps => qps.PrepServiceId).ToList())) .ReverseMap() .ForMember(dest => dest.Customer, opt => opt.Ignore()) .ForMember(dest => dest.OvenCost, opt => opt.Ignore()) .ForMember(dest => dest.PreparedBy, opt => opt.Ignore()) .ForMember(dest => dest.QuoteStatus, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.QuoteItems, opt => opt.Ignore()) .ForMember(dest => dest.QuotePrepServices, opt => opt.Ignore()) // Handled separately in controller .ForMember(dest => dest.ConvertedToJob, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // CreateQuoteDto -> Quote CreateMap() .ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.ProspectSmsConsentedAt, opt => opt.Ignore()) // Set by controller on consent .ForMember(dest => dest.QuoteNumber, opt => opt.Ignore()) // Generated by controller .ForMember(dest => dest.QuoteStatus, opt => opt.Ignore()) // Will be set by FK to Draft status .ForMember(dest => dest.OvenCost, opt => opt.Ignore()) .ForMember(dest => dest.SubTotal, opt => opt.Ignore()) // Calculated // Discount: map type and value from DTO, calculated fields ignored .ForMember(dest => dest.DiscountType, opt => opt.MapFrom(src => Enum.Parse(src.DiscountType))) .ForMember(dest => dest.DiscountValue, opt => opt.MapFrom(src => src.DiscountValue)) .ForMember(dest => dest.DiscountReason, opt => opt.MapFrom(src => src.DiscountReason)) .ForMember(dest => dest.DiscountPercent, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.DiscountAmount, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.TaxAmount, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.Total, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.QuoteItems, opt => opt.Ignore()) // Mapped separately .ForMember(dest => dest.QuotePrepServices, opt => opt.Ignore()) // Handled separately in controller .ForMember(dest => dest.Customer, opt => opt.Ignore()) .ForMember(dest => dest.PreparedBy, opt => opt.Ignore()) .ForMember(dest => dest.ConvertedToJob, opt => opt.Ignore()) .ForMember(dest => dest.PreparedById, opt => opt.Ignore()) .ForMember(dest => dest.ConvertedToJobId, opt => opt.Ignore()) .ForMember(dest => dest.ConvertedDate, opt => opt.Ignore()) .ForMember(dest => dest.SentDate, opt => opt.Ignore()) .ForMember(dest => dest.ApprovedDate, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // UpdateQuoteDto -> Quote CreateMap() .ForMember(dest => dest.QuoteNumber, opt => opt.Ignore()) // Cannot change .ForMember(dest => dest.ProspectSmsConsentedAt, opt => opt.Ignore()) // Managed by controller .ForMember(dest => dest.CustomerId, opt => opt.Ignore()) // Cannot change after creation - preserved in controller .ForMember(dest => dest.QuoteStatus, opt => opt.Ignore()) // Will be set by FK .ForMember(dest => dest.OvenCost, opt => opt.Ignore()) .ForMember(dest => dest.SubTotal, opt => opt.Ignore()) // Calculated // Discount: map type and value from DTO, calculated fields ignored .ForMember(dest => dest.DiscountType, opt => opt.MapFrom(src => Enum.Parse(src.DiscountType))) .ForMember(dest => dest.DiscountValue, opt => opt.MapFrom(src => src.DiscountValue)) .ForMember(dest => dest.DiscountReason, opt => opt.MapFrom(src => src.DiscountReason)) .ForMember(dest => dest.DiscountPercent, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.DiscountAmount, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.TaxAmount, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.Total, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.QuoteItems, opt => opt.Ignore()) // Mapped separately .ForMember(dest => dest.QuotePrepServices, opt => opt.Ignore()) // Handled separately in controller .ForMember(dest => dest.Customer, opt => opt.Ignore()) .ForMember(dest => dest.PreparedBy, opt => opt.Ignore()) .ForMember(dest => dest.ConvertedToJob, opt => opt.Ignore()) .ForMember(dest => dest.PreparedById, opt => opt.Ignore()) .ForMember(dest => dest.ConvertedToJobId, opt => opt.Ignore()) .ForMember(dest => dest.ConvertedDate, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // Quote -> UpdateQuoteDto CreateMap() .ForMember(dest => dest.IsForProspect, opt => opt.MapFrom(src => !src.CustomerId.HasValue)) .ForMember(dest => dest.QuoteStatusId, opt => opt.MapFrom(src => src.QuoteStatusId)); // ============================================================================ // QuoteItem Entity <-> DTOs // ============================================================================ // QuoteItem -> QuoteItemDto CreateMap() .ForMember(dest => dest.CatalogItemName, opt => opt.MapFrom(src => src.CatalogItem != null ? src.CatalogItem.Name : null)) .ForMember(dest => dest.Coats, opt => opt.MapFrom(src => src.Coats)) .ForMember(dest => dest.PrepServices, opt => opt.MapFrom(src => src.PrepServices)) .ReverseMap() .ForMember(dest => dest.Quote, opt => opt.Ignore()) .ForMember(dest => dest.CatalogItem, opt => opt.Ignore()) .ForMember(dest => dest.Coats, opt => opt.Ignore()) .ForMember(dest => dest.PrepServices, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.DeletedAt, opt => opt.Ignore()) .ForMember(dest => dest.DeletedBy, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // CreateQuoteItemDto -> QuoteItem CreateMap() .ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.QuoteId, opt => opt.Ignore()) .ForMember(dest => dest.UnitPrice, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.TotalPrice, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.Quote, opt => opt.Ignore()) .ForMember(dest => dest.Coats, opt => opt.Ignore()) // Mapped separately .ForMember(dest => dest.PrepServices, opt => opt.Ignore()) // Mapped separately .ForMember(dest => dest.CatalogItem, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.DeletedAt, opt => opt.Ignore()) .ForMember(dest => dest.DeletedBy, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // QuoteItem -> CreateQuoteItemDto (for Edit view) CreateMap() .ForMember(dest => dest.PrepServices, opt => opt.MapFrom(src => src.PrepServices)); // ============================================================================ // QuoteItemCoat Entity <-> DTOs // ============================================================================ // QuoteItemCoat -> QuoteItemCoatDto CreateMap() .ForMember(dest => dest.InventoryItemName, opt => opt.MapFrom(src => src.InventoryItem != null ? src.InventoryItem.Name : null)) .ForMember(dest => dest.VendorName, opt => opt.MapFrom(src => src.Vendor != null ? src.Vendor.CompanyName : null)) .ReverseMap() .ForMember(dest => dest.QuoteItem, opt => opt.Ignore()) .ForMember(dest => dest.InventoryItem, opt => opt.Ignore()) .ForMember(dest => dest.Vendor, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.DeletedAt, opt => opt.Ignore()) .ForMember(dest => dest.DeletedBy, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // CreateQuoteItemCoatDto -> QuoteItemCoat CreateMap() .ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.QuoteItemId, opt => opt.Ignore()) .ForMember(dest => dest.CoatMaterialCost, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.CoatLaborCost, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.CoatTotalCost, opt => opt.Ignore()) // Calculated .ForMember(dest => dest.QuoteItem, opt => opt.Ignore()) .ForMember(dest => dest.InventoryItem, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.DeletedAt, opt => opt.Ignore()) .ForMember(dest => dest.DeletedBy, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // QuoteItemCoat -> CreateQuoteItemCoatDto (for Edit view) CreateMap(); // ============================================================================ // QuoteItemPrepService Entity <-> DTOs // ============================================================================ // CreateQuoteItemPrepServiceDto -> QuoteItemPrepService CreateMap() .ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.QuoteItemId, opt => opt.Ignore()) .ForMember(dest => dest.QuoteItem, opt => opt.Ignore()) .ForMember(dest => dest.PrepService, opt => opt.Ignore()) .ForMember(dest => dest.BlastSetup, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.DeletedAt, opt => opt.Ignore()) .ForMember(dest => dest.DeletedBy, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // QuoteItemPrepService -> CreateQuoteItemPrepServiceDto (for Edit view) CreateMap() .ForMember(dest => dest.PrepServiceName, opt => opt.MapFrom(src => src.PrepService != null ? src.PrepService.ServiceName : null)); // ============================================================================ // Customer Conversion Mappings // ============================================================================ // Quote -> ConvertQuoteToCustomerDto CreateMap() .ForMember(dest => dest.QuoteId, opt => opt.MapFrom(src => src.Id)) .ForMember(dest => dest.CompanyName, opt => opt.MapFrom(src => src.ProspectCompanyName ?? "")) .ForMember(dest => dest.ContactName, opt => opt.MapFrom(src => src.ProspectContactName ?? "")) .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.ProspectEmail)) .ForMember(dest => dest.Phone, opt => opt.MapFrom(src => src.ProspectPhone)) .ForMember(dest => dest.Address, opt => opt.MapFrom(src => src.ProspectAddress)) .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.ProspectCity)) .ForMember(dest => dest.State, opt => opt.MapFrom(src => src.ProspectState)) .ForMember(dest => dest.ZipCode, opt => opt.MapFrom(src => src.ProspectZipCode)) .ForMember(dest => dest.IsCommercial, opt => opt.MapFrom(src => src.IsCommercial)) .ForMember(dest => dest.CreditLimit, opt => opt.MapFrom(src => 0m)) .ForMember(dest => dest.SmsConsent, opt => opt.MapFrom(src => src.ProspectSmsConsent)) .ForMember(dest => dest.ProspectSmsConsentedAt, opt => opt.MapFrom(src => src.ProspectSmsConsentedAt)) .ForMember(dest => dest.PricingTierId, opt => opt.Ignore()) .ForMember(dest => dest.TaxId, opt => opt.Ignore()) .ForMember(dest => dest.PaymentTerms, opt => opt.Ignore()) .ForMember(dest => dest.Notes, opt => opt.Ignore()); // ConvertQuoteToCustomerDto -> Customer CreateMap() .ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.ContactFirstName, opt => opt.MapFrom(src => src.ContactName)) .ForMember(dest => dest.ContactLastName, opt => opt.Ignore()) .ForMember(dest => dest.MobilePhone, opt => opt.Ignore()) .ForMember(dest => dest.Country, opt => opt.MapFrom(src => "USA")) .ForMember(dest => dest.CurrentBalance, opt => opt.MapFrom(src => 0m)) .ForMember(dest => dest.IsActive, opt => opt.MapFrom(src => true)) .ForMember(dest => dest.GeneralNotes, opt => opt.MapFrom(src => src.Notes)) .ForMember(dest => dest.LastContactDate, opt => opt.Ignore()) .ForMember(dest => dest.PricingTier, opt => opt.Ignore()) .ForMember(dest => dest.Jobs, opt => opt.Ignore()) .ForMember(dest => dest.Quotes, opt => opt.Ignore()) .ForMember(dest => dest.CustomerNotes, opt => opt.Ignore()) .ForMember(dest => dest.CompanyId, opt => opt.Ignore()) .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()); // ============================================================================ // QuoteChangeHistory Entity <-> DTOs // ============================================================================ // QuoteChangeHistory -> QuoteChangeHistoryDto CreateMap() .ForMember(dest => dest.ChangedByName, opt => opt.MapFrom(src => src.ChangedBy != null ? $"{src.ChangedBy.FirstName} {src.ChangedBy.LastName}" : src.ChangedByUserId == null ? "Customer" : "Unknown")); } }