cb7bbc37bd
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>
230 lines
8.5 KiB
C#
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; }
|
|
}
|