using PowderCoating.Core.Enums; namespace PowderCoating.Core.Entities; /// /// Represents a company/tenant in the multi-tenant system /// public class Company : BaseEntity { // Basic Information public string CompanyName { get; set; } = string.Empty; public string? CompanyCode { get; set; } // Short code (e.g., ABC) // Contact Information public string PrimaryContactName { get; set; } = string.Empty; public string PrimaryContactEmail { get; set; } = string.Empty; public string? Phone { get; set; } // Address public string? Address { get; set; } public string? City { get; set; } public string? State { get; set; } public string? ZipCode { get; set; } // Subscription/Status public bool IsActive { get; set; } = true; public DateTime SubscriptionStartDate { get; set; } = DateTime.UtcNow; public DateTime? SubscriptionEndDate { get; set; } public int SubscriptionPlan { get; set; } = 0; public SubscriptionStatus SubscriptionStatus { get; set; } = SubscriptionStatus.Active; public string? StripeCustomerId { get; set; } public string? StripeSubscriptionId { get; set; } /// /// When true the company has complimentary/internal access. /// All plan limits are treated as unlimited and the subscription /// expiry banner/lockout is suppressed regardless of SubscriptionEndDate. /// public bool IsComped { get; set; } = false; // Stripe Connect — online invoice payments public string? StripeAccountId { get; set; } // acct_xxx from OAuth public StripeConnectStatus StripeConnectStatus { get; set; } = StripeConnectStatus.NotConnected; public OnlinePaymentSurchargeType OnlinePaymentSurchargeType { get; set; } = OnlinePaymentSurchargeType.None; public decimal OnlinePaymentSurchargeValue { get; set; } = 0; // % or flat $ depending on type public bool OnlineSurchargeAcknowledged { get; set; } = false; // shop accepted compliance disclaimer /// Internal notes about manual subscription changes (not shown to the company). public string? SubscriptionNotes { get; set; } // Per-company limit overrides. null = use plan config default. -1 = unlimited. public int? MaxUsersOverride { get; set; } public int? MaxActiveJobsOverride { get; set; } public int? MaxCustomersOverride { get; set; } public int? MaxQuotesOverride { get; set; } public int? MaxCatalogItemsOverride { get; set; } public int? MaxJobPhotosOverride { get; set; } public int? MaxQuotePhotosOverride { get; set; } /// null = use plan config default. -1 = unlimited. 0 = disabled for this company. public int? MaxAiPhotoQuotesPerMonthOverride { get; set; } // AI Feature Flags (SuperAdmin-controlled per company) /// Enables/disables AI Photo Quote analysis for this company. public bool AiPhotoQuotesEnabled { get; set; } = true; /// Enables/disables the AI Inventory Assist lookup for this company. public bool AiInventoryAssistEnabled { get; set; } = true; /// Enables/disables the AI Catalog Price Check for this company. public bool AiCatalogPriceCheckEnabled { get; set; } = true; /// /// Stores the billing period the customer selected at registration (or last changed on the Billing page). /// true = annual billing, false = monthly billing. /// Used when redirecting to Stripe Checkout at trial-end so the right price ID is used automatically. /// public bool IsAnnualBilling { get; set; } = false; // Per-company feature overrides (SuperAdmin-controlled) /// /// null = use plan config default. /// true = force-enable online payments for this company regardless of plan. /// false = force-disable online payments for this company regardless of plan. /// public bool? OnlinePaymentsOverride { get; set; } /// /// null = use plan config default. /// true = force-enable accounting module for this company regardless of plan. /// false = force-disable accounting module for this company regardless of plan. /// public bool? AccountingOverride { get; set; } /// /// Company admin opt-in for SMS notifications. Defaults to false — company admin must /// explicitly accept the SMS terms of service before enabling. Has no effect if the plan /// does not allow SMS or if SmsDisabledByAdmin is true. /// public bool SmsEnabled { get; set; } = false; /// /// SuperAdmin force-disable for this company's SMS. When true, no SMS is sent regardless /// of plan or company settings. Use when a company is abusing SMS or requests a full opt-out. /// public bool SmsDisabledByAdmin { get; set; } = false; // Email marketing opt-out (CAN-SPAM compliance for platform broadcast emails) public bool MarketingEmailOptOut { get; set; } = false; public string MarketingUnsubscribeToken { get; set; } = Guid.NewGuid().ToString("N"); /// /// Determines whether financial reports (P&L, Balance Sheet, Cash Flow) use /// cash-basis or accrual-basis presentation. Switchable at any time — no GL /// re-posting occurs. Default is Accrual (standard for most businesses). /// public AccountingMethod AccountingMethod { get; set; } = AccountingMethod.Accrual; /// /// When set, prevents creating or editing accounting entries (JEs, bills, expenses) with dates /// on or before this date. Protects closed periods from accidental backdating. Null = no lock. /// public DateTime? BookLockedThrough { get; set; } // Settings public string? TimeZone { get; set; } = "America/New_York"; public byte[]? LogoData { get; set; } // Legacy - kept for backward compatibility public string? LogoContentType { get; set; } // Legacy - kept for backward compatibility public string? LogoFilePath { get; set; } // Filesystem path: /media/{CompanyId}/company-logo.{ext} // Kiosk /// /// Random token written to a long-lived HttpOnly cookie on the front-desk tablet when the /// owner activates the kiosk. Kiosk routes validate this token against the cookie so the /// tablet can serve the intake form without requiring a logged-in user. /// Null = kiosk not activated. Regenerate to revoke the current device. /// public string? KioskActivationToken { get; set; } // Navigation Properties public virtual ICollection Users { get; set; } = new List(); public virtual ICollection Customers { get; set; } = new List(); public virtual ICollection Jobs { get; set; } = new List(); public virtual ICollection Equipment { get; set; } = new List(); public virtual ICollection Quotes { get; set; } = new List(); public virtual ICollection InventoryItems { get; set; } = new List(); public virtual ICollection Vendors { get; set; } = new List(); public virtual ICollection PricingTiers { get; set; } = new List(); public virtual CompanyOperatingCosts? OperatingCosts { get; set; } public virtual CompanyPreferences? Preferences { get; set; } }