diff --git a/src/PowderCoating.Core/Enums/NotificationEnums.cs b/src/PowderCoating.Core/Enums/NotificationEnums.cs index 239013f..fb5ac58 100644 --- a/src/PowderCoating.Core/Enums/NotificationEnums.cs +++ b/src/PowderCoating.Core/Enums/NotificationEnums.cs @@ -13,6 +13,7 @@ public enum NotificationType InvoiceSent = 6, PaymentReceived = 7, QuoteDeclinedByCustomer = 8, + QuoteApprovedByCustomer = 16, PaymentReminder = 9, SubscriptionExpiryReminder = 10, SubscriptionExpired = 11, diff --git a/src/PowderCoating.Infrastructure/Data/SeedData.cs b/src/PowderCoating.Infrastructure/Data/SeedData.cs index 9909fe3..08a13c5 100644 --- a/src/PowderCoating.Infrastructure/Data/SeedData.cs +++ b/src/PowderCoating.Infrastructure/Data/SeedData.cs @@ -977,6 +977,28 @@ New accounts walk through an 18-step setup wizard to configure company informati CompanyId = companyId, CreatedAt = DateTime.UtcNow }, + new NotificationTemplate + { + NotificationType = NotificationType.QuoteApprovedByCustomer, + Channel = NotificationChannel.Email, + DisplayName = "Quote Approved by Customer (Internal)", + Subject = "Customer Response: Quote {{quoteNumber}} — {{companyName}}", + Body = "
Hello,
A customer has responded to quote {{quoteNumber}}.
Customer: {{customerName}}
Response: {{response}}
Log in to the portal to review and follow up.
", + IsActive = true, + CompanyId = companyId, + CreatedAt = DateTime.UtcNow + }, + new NotificationTemplate + { + NotificationType = NotificationType.QuoteDeclinedByCustomer, + Channel = NotificationChannel.Email, + DisplayName = "Quote Declined by Customer (Internal)", + Subject = "Customer Response: Quote {{quoteNumber}} — {{companyName}}", + Body = "Hello,
A customer has responded to quote {{quoteNumber}}.
Customer: {{customerName}}
Response: {{response}}
Log in to the portal to review and follow up.
", + IsActive = true, + CompanyId = companyId, + CreatedAt = DateTime.UtcNow + }, ]; } diff --git a/src/PowderCoating.Infrastructure/Services/NotificationService.cs b/src/PowderCoating.Infrastructure/Services/NotificationService.cs index becfa3f..5c07958 100644 --- a/src/PowderCoating.Infrastructure/Services/NotificationService.cs +++ b/src/PowderCoating.Infrastructure/Services/NotificationService.cs @@ -900,8 +900,12 @@ public class NotificationService : INotificationService ? $"Quote {quote.QuoteNumber} APPROVED — {customerName}" : $"Quote {quote.QuoteNumber} DECLINED — {customerName}"; + var notificationType = approved + ? NotificationType.QuoteApprovedByCustomer + : NotificationType.QuoteDeclinedByCustomer; + var (subject, htmlBody) = await GetRenderedEmailAsync( - quote.CompanyId, NotificationType.QuoteDeclinedByCustomer, values, defaultSubject); + quote.CompanyId, notificationType, values, defaultSubject); var fullHtml = AppendUnsubscribeFooterHtml(htmlBody, token: null, company, await GetBaseUrlAsync()); var plainText = StripHtml(fullHtml); @@ -913,7 +917,7 @@ public class NotificationService : INotificationService await WriteLog(new NotificationLog { Channel = NotificationChannel.Email, - NotificationType = NotificationType.QuoteDeclinedByCustomer, + NotificationType = notificationType, Status = success ? NotificationStatus.Sent : NotificationStatus.Failed, RecipientName = companyName, Recipient = companyEmail, @@ -1133,6 +1137,10 @@ public class NotificationService : INotificationService "Payment Received — Invoice {{invoiceNumber}}", "Dear {{customerName}},
We have received your payment of {{paymentAmount}} on {{paymentDate}} for invoice {{invoiceNumber}}.{{balanceDue}}
Thank you for your business with {{companyName}}.
" ), + [(NotificationType.QuoteApprovedByCustomer, NotificationChannel.Email)] = ( + "Customer Response: Quote {{quoteNumber}} — {{companyName}}", + "Hello,
A customer has responded to quote {{quoteNumber}}.
Customer: {{customerName}}
Response: {{response}}
Log in to the portal to review and follow up.
" + ), [(NotificationType.QuoteDeclinedByCustomer, NotificationChannel.Email)] = ( "Customer Response: Quote {{quoteNumber}} — {{companyName}}", "Hello,
A customer has responded to quote {{quoteNumber}}.
Customer: {{customerName}}
Response: {{response}}
Log in to the portal to review and follow up.
" diff --git a/src/PowderCoating.Web/Controllers/CompanySettingsController.cs b/src/PowderCoating.Web/Controllers/CompanySettingsController.cs index 61643c3..b1c15c7 100644 --- a/src/PowderCoating.Web/Controllers/CompanySettingsController.cs +++ b/src/PowderCoating.Web/Controllers/CompanySettingsController.cs @@ -2610,7 +2610,7 @@ public class CompanySettingsController : Controller // Quote types if (type is NotificationType.QuoteSent or NotificationType.QuoteApproved - or NotificationType.QuoteDeclinedByCustomer) + or NotificationType.QuoteApprovedByCustomer or NotificationType.QuoteDeclinedByCustomer) list.Add(("{{quoteNumber}}", "Quote number (e.g. QT-2501-0001)")); if (type == NotificationType.QuoteSent) @@ -2620,9 +2620,13 @@ public class CompanySettingsController : Controller list.Add(("{{approvalUrl}}", "Unique URL for the customer to view and approve the quote online")); } - if (type == NotificationType.QuoteDeclinedByCustomer) + if (type is NotificationType.QuoteApprovedByCustomer or NotificationType.QuoteDeclinedByCustomer) { list.Add(("{{response}}", "Customer's response — either \"APPROVED\" or \"DECLINED\"")); + } + + if (type == NotificationType.QuoteDeclinedByCustomer) + { list.Add(("{{declineReasonSection}}", "HTML block containing the decline reason — blank when the customer approved")); }