d5ad9fa073
- New CompanyPreferences.KioskIntakeOutput setting ("Quote" default / "Job"): controls
what the kiosk creates on submission; shown as a card-style radio toggle in
Company Settings → Kiosk tab
- KioskSession.LinkedQuoteId added so quote-first sessions link back to the draft quote
- Migration AddKioskIntakeOutputSetting applies both schema changes
- ProcessSubmissionAsync branches on setting: creates Draft quote (quote-first) or
Pending job (job-first); save order fixed (CompleteAsync before using DB-assigned Id as FK)
- Terms.cshtml pricing paragraph is now dynamic: "subject to formal quote" for Quote mode,
"team member will reach out about pricing" for Job mode
- Customer Intakes list: "View Quote" button appears when LinkedQuoteId is set
- Notification label fixed: Remote sessions now say "Remote Intake", not "Walk-in Intake"
- Inactivity reset shortened to 45 s on intake steps
- Signature pad: hosted locally (no CDN), canvas resize deferred via requestAnimationFrame
- AI photo upload: client-side compression to ≤1200px + AbortController 120 s timeout
- Help article and AI knowledge base updated with kiosk feature
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
150 lines
6.1 KiB
C#
150 lines
6.1 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
|
|
namespace PowderCoating.Application.DTOs.Company;
|
|
|
|
public class CompanyPreferencesDto
|
|
{
|
|
public int Id { get; set; }
|
|
public int CompanyId { get; set; }
|
|
|
|
// Application Defaults
|
|
public string DefaultCurrency { get; set; } = "USD";
|
|
public string DefaultDateFormat { get; set; } = "MM/dd/yyyy";
|
|
public string DefaultTimeFormat { get; set; } = "12h";
|
|
public string DefaultPaymentTerms { get; set; } = "Net 30";
|
|
public int DefaultQuoteValidityDays { get; set; } = 30;
|
|
public string QuoteNumberPrefix { get; set; } = "QT";
|
|
public string JobNumberPrefix { get; set; } = "JOB";
|
|
public bool UseMetricSystem { get; set; } = false;
|
|
|
|
// Job / Workflow
|
|
public string DefaultJobPriority { get; set; } = "Normal";
|
|
public bool RequireCustomerPO { get; set; }
|
|
public bool AllowCustomerApproval { get; set; } = true;
|
|
public int DefaultTurnaroundDays { get; set; } = 7;
|
|
// Email Sender Identity
|
|
public string? EmailFromAddress { get; set; }
|
|
public string? EmailFromName { get; set; }
|
|
|
|
// Notifications
|
|
public bool EmailNotificationsEnabled { get; set; } = true;
|
|
public bool NotifyOnNewJob { get; set; } = true;
|
|
public bool NotifyOnNewQuote { get; set; } = true;
|
|
public bool NotifyOnJobStatusChange { get; set; } = true;
|
|
public bool NotifyOnQuoteApproval { get; set; } = true;
|
|
public bool NotifyOnPaymentReceived { get; set; } = true;
|
|
public int QuoteExpiryWarningDays { get; set; } = 3;
|
|
public int DueDateWarningDays { get; set; } = 2;
|
|
public int MaintenanceAlertDays { get; set; } = 7;
|
|
public bool PaymentRemindersEnabled { get; set; } = false;
|
|
public string PaymentReminderDays { get; set; } = "7,14,30";
|
|
|
|
// Data Retention
|
|
public int QuoteRetentionYears { get; set; } = 7;
|
|
public int JobRetentionYears { get; set; } = 7;
|
|
public int LogRetentionDays { get; set; } = 90;
|
|
public int AutoArchiveJobsDays { get; set; } = 365;
|
|
public int DeletedRecordRetentionDays { get; set; } = 30;
|
|
|
|
// Quote PDF Template
|
|
public string QtAccentColor { get; set; } = "#374151";
|
|
public string? QtDefaultTerms { get; set; }
|
|
public string? QtFooterNote { get; set; }
|
|
|
|
// Invoice PDF Template
|
|
public string InAccentColor { get; set; } = "#374151";
|
|
public string? InDefaultTerms { get; set; }
|
|
public string? InFooterNote { get; set; }
|
|
|
|
// Blank Work Order PDF Template
|
|
public string WoAccentColor { get; set; } = "#374151";
|
|
public string? WoTerms { get; set; }
|
|
|
|
// Kiosk settings
|
|
public string KioskIntakeOutput { get; set; } = "Quote";
|
|
}
|
|
|
|
public class UpdateAppDefaultsDto
|
|
{
|
|
[Required, StringLength(3)] public string DefaultCurrency { get; set; } = "USD";
|
|
[Required, StringLength(20)] public string DefaultDateFormat { get; set; } = "MM/dd/yyyy";
|
|
[Required] public string DefaultTimeFormat { get; set; } = "12h";
|
|
[Required, StringLength(50)] public string DefaultPaymentTerms { get; set; } = "Net 30";
|
|
[Range(1, 365)] public int DefaultQuoteValidityDays { get; set; } = 30;
|
|
[Required, StringLength(10)] public string QuoteNumberPrefix { get; set; } = "QT";
|
|
[Required, StringLength(10)] public string JobNumberPrefix { get; set; } = "JOB";
|
|
public bool UseMetricSystem { get; set; } = false;
|
|
}
|
|
|
|
public class UpdateJobDefaultsDto
|
|
{
|
|
[Required] public string DefaultJobPriority { get; set; } = "Normal";
|
|
public bool RequireCustomerPO { get; set; }
|
|
public bool AllowCustomerApproval { get; set; }
|
|
[Range(1, 365)] public int DefaultTurnaroundDays { get; set; } = 7;
|
|
}
|
|
|
|
public class UpdateNotificationsDto
|
|
{
|
|
[EmailAddress(ErrorMessage = "Invalid email address format.")]
|
|
[StringLength(100)]
|
|
[Display(Name = "From Email Address")]
|
|
public string? EmailFromAddress { get; set; }
|
|
|
|
[StringLength(100)]
|
|
[Display(Name = "From Display Name")]
|
|
public string? EmailFromName { get; set; }
|
|
|
|
public bool EmailNotificationsEnabled { get; set; }
|
|
public bool NotifyOnNewJob { get; set; }
|
|
public bool NotifyOnNewQuote { get; set; }
|
|
public bool NotifyOnJobStatusChange { get; set; }
|
|
public bool NotifyOnQuoteApproval { get; set; }
|
|
public bool NotifyOnPaymentReceived { get; set; }
|
|
[Range(0, 30)] public int QuoteExpiryWarningDays { get; set; } = 3;
|
|
[Range(0, 30)] public int DueDateWarningDays { get; set; } = 2;
|
|
[Range(0, 90)] public int MaintenanceAlertDays { get; set; } = 7;
|
|
public bool PaymentRemindersEnabled { get; set; } = false;
|
|
[StringLength(50)] public string PaymentReminderDays { get; set; } = "7,14,30";
|
|
}
|
|
|
|
public class UpdateDataRetentionDto
|
|
{
|
|
[Range(1, 99)] public int QuoteRetentionYears { get; set; } = 7;
|
|
[Range(1, 99)] public int JobRetentionYears { get; set; } = 7;
|
|
[Range(30, 3650)] public int LogRetentionDays { get; set; } = 90;
|
|
[Range(30, 3650)] public int AutoArchiveJobsDays { get; set; } = 365;
|
|
[Range(7, 365)] public int DeletedRecordRetentionDays { get; set; } = 30;
|
|
}
|
|
|
|
public class UpdateQuoteTemplateDto
|
|
{
|
|
[RegularExpression(@"^#[0-9A-Fa-f]{6}$", ErrorMessage = "Accent color must be a valid hex color (e.g. #374151)")]
|
|
public string QtAccentColor { get; set; } = "#374151";
|
|
[StringLength(3000)] public string? QtDefaultTerms { get; set; }
|
|
[StringLength(200)] public string? QtFooterNote { get; set; }
|
|
}
|
|
|
|
public class UpdateInvoiceTemplateDto
|
|
{
|
|
[RegularExpression(@"^#[0-9A-Fa-f]{6}$", ErrorMessage = "Accent color must be a valid hex color (e.g. #374151)")]
|
|
public string InAccentColor { get; set; } = "#374151";
|
|
[StringLength(3000)] public string? InDefaultTerms { get; set; }
|
|
[StringLength(200)] public string? InFooterNote { get; set; }
|
|
}
|
|
|
|
public class UpdateWorkOrderTemplateDto
|
|
{
|
|
[RegularExpression(@"^#[0-9A-Fa-f]{6}$", ErrorMessage = "Accent color must be a valid hex color (e.g. #374151)")]
|
|
public string WoAccentColor { get; set; } = "#374151";
|
|
[StringLength(2000)] public string? WoTerms { get; set; }
|
|
}
|
|
|
|
|
|
public class UpdateKioskSettingsDto
|
|
{
|
|
/// <summary>"Quote" (default) or "Job" — what the kiosk creates on submission.</summary>
|
|
[Required]
|
|
public string KioskIntakeOutput { get; set; } = "Quote";
|
|
}
|