6569d9c4ea
- Three-tier SMS gate: platform kill-switch → admin force-disable → plan AllowSms → company opt-in - CompanySmsAgreement entity records admin acceptance of TCPA terms with IP, user agent, and terms version - SMS terms of service modal on Company Settings with versioned re-agreement (AppConstants.SmsTermsVersion) - Dev redirect: non-production SMS routed to Twilio:DevRedirectPhone to protect real customer numbers - Removed redundant Ready for Pickup SMS (Job Completed covers it) - Role-based compose modal on job completion: Admin/Manager reviews and edits before send; ShopFloor auto-sends - Send SMS button on job details for ad-hoc messages (Admin/Manager only) - SendJobSmsAsync auto-appends STOP opt-out language if missing - Migrations: AddSmsGating, AddCompanySmsAgreement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
80 lines
3.1 KiB
C#
80 lines
3.1 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
|
|
namespace PowderCoating.Application.DTOs.Subscription;
|
|
|
|
public class SubscriptionPlanConfigDto
|
|
{
|
|
public int Id { get; set; }
|
|
public int Plan { get; set; }
|
|
public string DisplayName { get; set; } = string.Empty;
|
|
public string? Description { get; set; }
|
|
public int MaxUsers { get; set; }
|
|
public int MaxActiveJobs { get; set; }
|
|
public int MaxCustomers { get; set; }
|
|
public int MaxQuotes { get; set; }
|
|
public int MaxCatalogItems { get; set; }
|
|
public int MaxJobPhotos { get; set; }
|
|
public int MaxQuotePhotos { get; set; }
|
|
public int MaxAiPhotoQuotesPerMonth { get; set; }
|
|
public decimal MonthlyPrice { get; set; }
|
|
public decimal AnnualPrice { get; set; }
|
|
public string? StripePriceIdMonthly { get; set; }
|
|
public string? StripePriceIdAnnual { get; set; }
|
|
public bool AllowOnlinePayments { get; set; }
|
|
public bool AllowAccounting { get; set; }
|
|
public bool AllowAiPhotoQuotes { get; set; }
|
|
public bool AllowAiInventoryAssist { get; set; }
|
|
public bool AllowAiCatalogPriceCheck { get; set; }
|
|
public bool AllowSms { get; set; }
|
|
public bool IsActive { get; set; }
|
|
public int SortOrder { get; set; }
|
|
}
|
|
|
|
public class UpdateSubscriptionPlanConfigDto
|
|
{
|
|
public int Id { get; set; }
|
|
public string? Description { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxUsers { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxActiveJobs { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxCustomers { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxQuotes { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxCatalogItems { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxJobPhotos { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxQuotePhotos { get; set; }
|
|
|
|
[Range(-1, int.MaxValue, ErrorMessage = "Value must be -1 (unlimited) or a positive number")]
|
|
public int MaxAiPhotoQuotesPerMonth { get; set; }
|
|
|
|
[Range(0, 99999, ErrorMessage = "Price must be between 0 and 99999")]
|
|
public decimal MonthlyPrice { get; set; }
|
|
|
|
[Range(0, 99999, ErrorMessage = "Price must be between 0 and 99999")]
|
|
public decimal AnnualPrice { get; set; }
|
|
|
|
public string? StripePriceIdMonthly { get; set; }
|
|
public string? StripePriceIdAnnual { get; set; }
|
|
|
|
public bool AllowOnlinePayments { get; set; }
|
|
public bool AllowAccounting { get; set; }
|
|
public bool AllowAiPhotoQuotes { get; set; }
|
|
public bool AllowAiInventoryAssist { get; set; }
|
|
public bool AllowAiCatalogPriceCheck { get; set; }
|
|
public bool AllowSms { get; set; }
|
|
|
|
public bool IsActive { get; set; }
|
|
}
|