Files
PowderCoatingLogix/src/PowderCoating.Core/Entities/Customer.cs
T
spouliot fb979bc88d Add BillingEmail field for commercial customers; support comma-separated multi-email
- Customer entity + DTO: new BillingEmail field (accounting/invoicing address)
- Email fields now accept comma-separated lists; DTO validates each address individually
- NotificationService: SendToEmailListAsync helper fans out to all addresses in a list;
  NotifyQuoteSentAsync accepts optional overrideEmail so staff can send to an ad-hoc address
- Migration: AddCustomerBillingEmail
- Customer Create/Edit/Details views updated to show Billing Email field
- customer-billing-email.js: client-side helpers for billing email input

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 20:46:53 -04:00

59 lines
2.6 KiB
C#

namespace PowderCoating.Core.Entities;
public class Customer : BaseEntity
{
public string? CompanyName { get; set; }
public string? ContactFirstName { get; set; }
public string? ContactLastName { get; set; }
public string? Email { get; set; }
public string? BillingEmail { get; set; } // Accounting/invoicing email for commercial customers
public string? Phone { get; set; }
public string? MobilePhone { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? ZipCode { get; set; }
public string? Country { get; set; } = "USA";
// Business Information
public bool IsCommercial { get; set; }
public string? TaxId { get; set; }
public decimal CreditLimit { get; set; }
public decimal CurrentBalance { get; set; }
public decimal CreditBalance { get; set; } // Available store credit (credit memos)
public string? PaymentTerms { get; set; }
public int? PricingTierId { get; set; }
// Tax Exemption
public bool IsTaxExempt { get; set; }
public byte[]? TaxExemptCertificateData { get; set; }
public string? TaxExemptCertificateContentType { get; set; }
public string? TaxExemptCertificateFileName { get; set; }
// Relationships
public virtual PricingTier? PricingTier { get; set; }
public virtual ICollection<Job> Jobs { get; set; } = new List<Job>();
public virtual ICollection<Quote> Quotes { get; set; } = new List<Quote>();
public virtual ICollection<CustomerNote> CustomerNotes { get; set; } = new List<CustomerNote>();
// Additional fields
public string? GeneralNotes { get; set; }
public bool IsActive { get; set; } = true;
public DateTime? LastContactDate { get; set; }
// Notification preferences
public bool NotifyByEmail { get; set; } = true;
// NotifyBySms is only set to true after explicit staff-recorded consent (TCPA compliance)
public bool NotifyBySms { get; set; } = false;
// Unique token used in email unsubscribe links (no auth required)
public string UnsubscribeToken { get; set; } = Guid.NewGuid().ToString("N");
// SMS consent tracking (TCPA compliance)
public DateTime? SmsConsentedAt { get; set; }
public string? SmsConsentMethod { get; set; }
/// <summary>Set when the customer replies STOP or is manually opted out. Null means they have never opted out.</summary>
public DateTime? SmsOptedOutAt { get; set; }
public virtual ICollection<NotificationLog> NotificationLogs { get; set; } = new List<NotificationLog>();
public virtual ICollection<Invoice> Invoices { get; set; } = new List<Invoice>();
}