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>
55 lines
3.5 KiB
C#
55 lines
3.5 KiB
C#
using PowderCoating.Core.Enums;
|
|
|
|
namespace PowderCoating.Core.Entities;
|
|
|
|
/// <summary>
|
|
/// Represents one customer self-service intake session — either completed on the front-desk tablet
|
|
/// (InPerson) or via an emailed link the customer fills out on their own device (Remote).
|
|
/// Sessions are tenant-scoped and soft-deletable. Load anonymous sessions with ignoreQueryFilters:true.
|
|
/// </summary>
|
|
public class KioskSession : BaseEntity
|
|
{
|
|
/// <summary>URL-safe GUID used in all kiosk routes; unique across the table.</summary>
|
|
public Guid SessionToken { get; set; } = Guid.NewGuid();
|
|
|
|
public KioskSessionType SessionType { get; set; }
|
|
public KioskSessionStatus Status { get; set; } = KioskSessionStatus.Active;
|
|
|
|
// ── Step 1 — Contact ─────────────────────────────────────────────────────
|
|
public string CustomerFirstName { get; set; } = string.Empty;
|
|
public string CustomerLastName { get; set; } = string.Empty;
|
|
public string CustomerPhone { get; set; } = string.Empty;
|
|
public string CustomerEmail { get; set; } = string.Empty;
|
|
public bool IsReturningCustomer { get; set; }
|
|
|
|
// ── Step 2 — Job Description ──────────────────────────────────────────────
|
|
public string JobDescription { get; set; } = string.Empty;
|
|
public string? HowDidYouHearAboutUs { get; set; }
|
|
|
|
// ── Step 3 — Terms & Consent ──────────────────────────────────────────────
|
|
public bool AgreedToTerms { get; set; }
|
|
public DateTime? AgreedToTermsAt { get; set; }
|
|
/// <summary>Customer opted in to SMS order updates; sets Customer.NotifyBySms on submission.</summary>
|
|
public bool SmsOptIn { get; set; }
|
|
/// <summary>Base-64 PNG from signature_pad; null for Remote sessions (no drawn signature required).</summary>
|
|
public string? SignatureDataBase64 { get; set; }
|
|
|
|
// ── Outcome ───────────────────────────────────────────────────────────────
|
|
public int? LinkedCustomerId { get; set; }
|
|
/// <summary>Set when KioskIntakeOutput = "Job". Null when a Quote was created instead.</summary>
|
|
public int? LinkedJobId { get; set; }
|
|
/// <summary>Set when KioskIntakeOutput = "Quote". Null when a Job was created instead.</summary>
|
|
public int? LinkedQuoteId { get; set; }
|
|
public DateTime? SubmittedAt { get; set; }
|
|
/// <summary>Sessions auto-expire 2 h after creation (InPerson) or 48 h (Remote). ExpiresAt is set at creation.</summary>
|
|
public DateTime ExpiresAt { get; set; }
|
|
|
|
// ── Remote-only ───────────────────────────────────────────────────────────
|
|
public string? RemoteLinkEmail { get; set; }
|
|
public DateTime? RemoteLinkSentAt { get; set; }
|
|
|
|
// ── Navigation ────────────────────────────────────────────────────────────
|
|
public virtual Customer? LinkedCustomer { get; set; }
|
|
public virtual Job? LinkedJob { get; set; }
|
|
}
|