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>
116 lines
5.9 KiB
C#
116 lines
5.9 KiB
C#
namespace PowderCoating.Core.Entities;
|
|
|
|
/// <summary>
|
|
/// Company-specific application and workflow preferences
|
|
/// </summary>
|
|
public class CompanyPreferences : BaseEntity
|
|
{
|
|
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 string InvoiceNumberPrefix { get; set; } = "INV";
|
|
public bool UseMetricSystem { get; set; } = false; // False = Imperial (ft, lb), True = Metric (m, kg)
|
|
|
|
// Job / Workflow Defaults
|
|
public string DefaultJobPriority { get; set; } = "Normal";
|
|
public bool RequireCustomerPO { get; set; } = false;
|
|
public bool AllowCustomerApproval { get; set; } = true;
|
|
public int DefaultTurnaroundDays { get; set; } = 7;
|
|
// Email Sender Identity
|
|
/// <summary>From address used in outgoing emails. Falls back to SendGrid:FromEmail in appsettings when null.</summary>
|
|
public string? EmailFromAddress { get; set; }
|
|
/// <summary>From display name used in outgoing emails. Falls back to SendGrid:FromName in appsettings when null.</summary>
|
|
public string? EmailFromName { get; set; }
|
|
|
|
// Notifications & Alerts
|
|
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;
|
|
|
|
// Payment Reminders
|
|
/// <summary>When true, the background service will send overdue payment reminder emails.</summary>
|
|
public bool PaymentRemindersEnabled { get; set; } = false;
|
|
/// <summary>Comma-separated days-past-due thresholds at which reminders are sent (e.g. "7,14,30").</summary>
|
|
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; }
|
|
|
|
// Setup Wizard Progress
|
|
public bool SetupWizardStarted { get; set; } = false;
|
|
public bool SetupWizardCompleted { get; set; } = false;
|
|
/// <summary>Comma-separated step numbers that have been completed (e.g. "1,2,3")</summary>
|
|
public string? SetupWizardDoneSteps { get; set; }
|
|
/// <summary>Comma-separated step numbers the user chose to skip</summary>
|
|
public string? SetupWizardSkippedSteps { get; set; }
|
|
/// <summary>UTC timestamp of when the setup wizard was completed. Null if not yet completed.</summary>
|
|
public DateTime? SetupWizardCompletedAt { get; set; }
|
|
/// <summary>ASP.NET Identity user ID of the user who completed the setup wizard.</summary>
|
|
public string? SetupWizardCompletedByUserId { get; set; }
|
|
/// <summary>Display name of the user who completed the setup wizard, stored at completion time
|
|
/// to avoid a runtime JOIN to the Identity tables when listing companies.</summary>
|
|
public string? SetupWizardCompletedByName { get; set; }
|
|
/// <summary>True when the company indicated they are migrating data from QuickBooks Desktop.</summary>
|
|
public bool MigratingFromQuickBooks { get; set; } = false;
|
|
/// <summary>JSON blob persisting QB Migration Wizard step state across sessions.</summary>
|
|
public string? QbMigrationStateJson { get; set; }
|
|
|
|
// Kiosk settings
|
|
/// <summary>
|
|
/// Controls what the kiosk creates on submission: "Quote" (default) or "Job".
|
|
/// Quote aligns with the default Terms text ("subject to a formal quote").
|
|
/// Job is for shops that price on the spot and want the work order ready immediately.
|
|
/// </summary>
|
|
public string KioskIntakeOutput { get; set; } = "Quote";
|
|
|
|
// Guided activation / first-workflow onboarding
|
|
/// <summary>Selected first-workflow path: quote_first or job_first. Null until chosen.</summary>
|
|
public string? OnboardingPath { get; set; }
|
|
/// <summary>True once the company completes its first guided real workflow.</summary>
|
|
public bool FirstWorkflowCompleted { get; set; } = false;
|
|
/// <summary>UTC timestamp of when the first guided workflow was completed.</summary>
|
|
public DateTime? FirstWorkflowCompletedAt { get; set; }
|
|
/// <summary>UTC timestamp of the company's first quote creation.</summary>
|
|
public DateTime? FirstQuoteCreatedAt { get; set; }
|
|
/// <summary>UTC timestamp of the company's first job creation.</summary>
|
|
public DateTime? FirstJobCreatedAt { get; set; }
|
|
/// <summary>UTC timestamp of the company's first invoice creation.</summary>
|
|
public DateTime? FirstInvoiceCreatedAt { get; set; }
|
|
/// <summary>UTC timestamp of when the company dismissed guided activation without completing it.</summary>
|
|
public DateTime? GuidedActivationDismissedAt { get; set; }
|
|
|
|
// Navigation
|
|
public virtual Company Company { get; set; } = null!;
|
|
}
|