Files
PowderCoatingLogix/src/PowderCoating.Application/DTOs/Company/CompanyDtos.cs
T
spouliot cb7bbc37bd Add three-layer feature gating for AI Catalog Price Check
Adds platform-level, plan-level (Enterprise only), and per-company
toggles for the AI Catalog Price Check feature. Includes:
- Company.AiCatalogPriceCheckEnabled per-company flag
- SubscriptionPlanConfig.AllowAiCatalogPriceCheck plan-level flag
- PlatformSetting 'AiCatalogPriceCheckEnabled' global kill switch
- IPlatformSettingsService.GetBoolAsync helper
- ISubscriptionService.CanUseAiCatalogPriceCheckAsync
- UI controls in Companies/Edit, PlatformSubscription/Edit+Index,
  and SubscriptionManagement/Manage
- Migration AddAiCatalogPriceCheckGating applied

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:29:51 -04:00

230 lines
8.5 KiB
C#

using System.ComponentModel.DataAnnotations;
using PowderCoating.Application.DTOs.User;
using PowderCoating.Core.Enums;
namespace PowderCoating.Application.DTOs.Company;
/// <summary>
/// Full company details DTO
/// </summary>
public class CompanyDto
{
public int Id { get; set; }
public string CompanyName { get; set; } = string.Empty;
public string? CompanyCode { get; set; }
public string PrimaryContactName { get; set; } = string.Empty;
public string PrimaryContactEmail { get; set; } = string.Empty;
public string? Phone { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? ZipCode { get; set; }
public bool IsActive { get; set; }
public DateTime SubscriptionStartDate { get; set; }
public DateTime? SubscriptionEndDate { get; set; }
public int SubscriptionPlan { get; set; }
public SubscriptionStatus SubscriptionStatus { get; set; }
public string? StripeCustomerId { get; set; }
public string? StripeSubscriptionId { get; set; }
public string? TimeZone { get; set; }
public string? LogoPath { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public string? CreatedBy { get; set; }
public string? UpdatedBy { get; set; }
// Statistics
public int UserCount { get; set; }
public int CustomerCount { get; set; }
public int JobCount { get; set; }
// Users list for management
public List<CompanyUserDto> Users { get; set; } = new List<CompanyUserDto>();
}
/// <summary>
/// Company list item DTO for grid/list views
/// </summary>
public class CompanyListDto
{
public int Id { get; set; }
public string CompanyName { get; set; } = string.Empty;
public string? CompanyCode { get; set; }
public string PrimaryContactEmail { get; set; } = string.Empty;
public string? Phone { get; set; }
public int SubscriptionPlan { get; set; }
public SubscriptionStatus SubscriptionStatus { get; set; }
public bool IsActive { get; set; }
public DateTime SubscriptionStartDate { get; set; }
public DateTime? SubscriptionEndDate { get; set; }
public int UserCount { get; set; }
public int JobCount { get; set; }
public int QuoteCount { get; set; }
public int CustomerCount { get; set; }
public DateTime CreatedAt { get; set; }
public bool WizardCompleted { get; set; }
public DateTime? WizardCompletedAt { get; set; }
public string? WizardCompletedByName { get; set; }
}
/// <summary>
/// DTO for creating a new company
/// </summary>
public class CreateCompanyDto
{
[Required(ErrorMessage = "Company name is required")]
[StringLength(200, ErrorMessage = "Company name cannot exceed 200 characters")]
public string CompanyName { get; set; } = string.Empty;
[StringLength(10, ErrorMessage = "Company code cannot exceed 10 characters")]
public string? CompanyCode { get; set; }
[Required(ErrorMessage = "Primary contact name is required")]
[StringLength(100, ErrorMessage = "Contact name cannot exceed 100 characters")]
public string PrimaryContactName { get; set; } = string.Empty;
[Required(ErrorMessage = "Primary contact email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
public string PrimaryContactEmail { get; set; } = string.Empty;
[Phone(ErrorMessage = "Invalid phone number")]
public string? Phone { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
[StringLength(2, ErrorMessage = "State code must be 2 characters")]
public string? State { get; set; }
public string? ZipCode { get; set; }
public bool IsActive { get; set; } = true;
[Required(ErrorMessage = "Subscription start date is required")]
public DateTime SubscriptionStartDate { get; set; } = DateTime.UtcNow;
public DateTime? SubscriptionEndDate { get; set; }
public int SubscriptionPlan { get; set; } = 0;
public string? TimeZone { get; set; } = "America/New_York";
// Initial admin user details
[Required(ErrorMessage = "Admin first name is required")]
public string AdminFirstName { get; set; } = string.Empty;
[Required(ErrorMessage = "Admin last name is required")]
public string AdminLastName { get; set; } = string.Empty;
[Required(ErrorMessage = "Admin email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
public string AdminEmail { get; set; } = string.Empty;
[Required(ErrorMessage = "Admin password is required")]
[StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be at least 8 characters long")]
[RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#^()_+=\-\[\]{};':""\\|,.<>\/`~])[A-Za-z\d@$!%*?&#^()_+=\-\[\]{};':""\\|,.<>\/`~]{8,}$",
ErrorMessage = "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character")]
public string AdminPassword { get; set; } = string.Empty;
}
/// <summary>
/// DTO for updating an existing company
/// </summary>
public class UpdateCompanyDto
{
public int Id { get; set; }
public string CompanyName { get; set; } = string.Empty;
public string? CompanyCode { get; set; }
public string PrimaryContactName { get; set; } = string.Empty;
public string PrimaryContactEmail { get; set; } = string.Empty;
public string? Phone { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? ZipCode { get; set; }
public bool IsActive { get; set; }
public DateTime SubscriptionStartDate { get; set; }
public DateTime? SubscriptionEndDate { get; set; }
public int SubscriptionPlan { get; set; }
// AI feature flags
public bool AiPhotoQuotesEnabled { get; set; }
public bool AiInventoryAssistEnabled { get; set; }
public bool AiCatalogPriceCheckEnabled { get; set; }
public int? MaxAiPhotoQuotesPerMonthOverride { get; set; }
// Per-company feature overrides (null = use plan default)
public bool? OnlinePaymentsOverride { get; set; }
public bool? AccountingOverride { get; set; }
public string? TimeZone { get; set; }
}
/// <summary>
/// DTO for creating a company admin user (SuperAdmin only)
/// </summary>
public class CreateCompanyAdminDto
{
public int CompanyId { get; set; }
[Required]
public string CompanyName { get; set; } = string.Empty;
[Required(ErrorMessage = "First name is required")]
[StringLength(100, ErrorMessage = "First name cannot exceed 100 characters")]
[Display(Name = "First Name")]
public string FirstName { get; set; } = string.Empty;
[Required(ErrorMessage = "Last name is required")]
[StringLength(100, ErrorMessage = "Last name cannot exceed 100 characters")]
[Display(Name = "Last Name")]
public string LastName { get; set; } = string.Empty;
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
[Display(Name = "Email")]
public string Email { get; set; } = string.Empty;
[Required(ErrorMessage = "Password is required")]
[StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be at least 8 characters long")]
[RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#^()_+=\-\[\]{};':""\\|,.<>\/`~])[A-Za-z\d@$!%*?&#^()_+=\-\[\]{};':""\\|,.<>\/`~]{8,}$",
ErrorMessage = "Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character")]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; } = string.Empty;
[Phone(ErrorMessage = "Invalid phone number")]
[Display(Name = "Phone")]
public string? Phone { get; set; }
[StringLength(100, ErrorMessage = "Department cannot exceed 100 characters")]
[Display(Name = "Department")]
public string? Department { get; set; }
[StringLength(100, ErrorMessage = "Position cannot exceed 100 characters")]
[Display(Name = "Position")]
public string? Position { get; set; }
}
/// <summary>
/// Simplified company info DTO for PDF generation (avoids circular dependencies)
/// </summary>
public class CompanyInfoDto
{
public string CompanyName { get; set; } = string.Empty;
public string? Phone { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? ZipCode { get; set; }
public string? PrimaryContactEmail { get; set; }
}