f40d58ac2e
- Quote entity: ProspectSmsConsent (bool) + ProspectSmsConsentedAt (DateTime?) fields - QuoteDtos: consent fields on Create/Update/Convert DTOs with TCPA guidance text - Quote Create/Edit views: SMS consent checkbox shown when mobile number is entered - Quote ConvertToCustomer view: staff must re-confirm consent carries over to customer record - QuoteApproval: consent state exposed in ViewModel and ApprovalPage for transparency - Consent timestamp cleared when prospect quote is linked to an existing customer - Migration: AddProspectSmsConsent Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
336 lines
17 KiB
Plaintext
336 lines
17 KiB
Plaintext
@model PowderCoating.Application.DTOs.Quote.ConvertQuoteToCustomerDto
|
|
|
|
@{
|
|
ViewData["Title"] = "Convert Prospect/Walk-In to Customer";
|
|
ViewData["PageIcon"] = "bi-arrow-right-circle-fill";
|
|
}
|
|
|
|
<div class="container-fluid mt-4">
|
|
<div class="mb-4">
|
|
<p class="text-muted">Quote: <strong>@Model.QuoteNumber</strong></p>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<form asp-action="ConvertToCustomer" method="post">
|
|
<input type="hidden" asp-for="QuoteId" />
|
|
<input type="hidden" asp-for="QuoteNumber" />
|
|
<partial name="_ValidationSummary" />
|
|
|
|
<!-- Quote Summary (Read-Only) -->
|
|
<div class="card mb-4">
|
|
<div class="card-header bg-info text-white">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-file-text me-2"></i>Quote Summary
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<p><strong>Quote Number:</strong> @Model.QuoteNumber</p>
|
|
<p><strong>Current Prospect/Walk-In:</strong> @(Model.CompanyName ?? Model.ContactName ?? "Unknown")</p>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<p><strong>Email:</strong> @(Model.Email ?? "-")</p>
|
|
<p><strong>Phone:</strong> @(Model.Phone ?? "-")</p>
|
|
</div>
|
|
</div>
|
|
<div class="alert alert-warning mb-0">
|
|
<i class="bi bi-exclamation-triangle me-2"></i>
|
|
<strong>Note:</strong> Converting this prospect will create a new customer record
|
|
and link this quote to that customer. The quote status will change to "Converted".
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Customer Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-building me-2"></i>Customer Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="mb-3">
|
|
<label asp-for="IsCommercial" class="form-label">Customer Type</label>
|
|
<select asp-for="IsCommercial" class="form-select" id="customerTypeSelect" onchange="toggleCompanyNameRequired()">
|
|
<option value="false">Individual</option>
|
|
<option value="true">Commercial</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="CompanyName" class="form-label">
|
|
Company Name <span id="companyNameRequired" class="text-danger" style="display:none;">*</span>
|
|
</label>
|
|
<input asp-for="CompanyName" class="form-control" />
|
|
<span asp-validation-for="CompanyName" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="ContactName" class="form-label">Contact Name <span class="text-danger">*</span></label>
|
|
<input asp-for="ContactName" class="form-control" placeholder="First and last name" />
|
|
<span asp-validation-for="ContactName" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-12 mb-2">
|
|
<small class="text-muted"><span class="text-danger">*</span> At least one of email or phone is required.</small>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="Email" class="form-label">Email</label>
|
|
<input asp-for="Email" class="form-control" type="email" placeholder="customer@example.com" />
|
|
<span asp-validation-for="Email" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="Phone" class="form-label">Phone</label>
|
|
<input asp-for="Phone" class="form-control" type="tel" placeholder="(555) 000-0000" />
|
|
<span asp-validation-for="Phone" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Address Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-geo-alt me-2"></i>Address Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="mb-3">
|
|
<label asp-for="Address" class="form-label"></label>
|
|
<input asp-for="Address" class="form-control" />
|
|
<span asp-validation-for="Address" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="City" class="form-label"></label>
|
|
<input asp-for="City" class="form-control" />
|
|
<span asp-validation-for="City" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label asp-for="State" class="form-label"></label>
|
|
<input asp-for="State" class="form-control" maxlength="2" />
|
|
<span asp-validation-for="State" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label asp-for="ZipCode" class="form-label"></label>
|
|
<input asp-for="ZipCode" class="form-control" />
|
|
<span asp-validation-for="ZipCode" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Additional Customer Details -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-gear me-2"></i>Additional Details
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="TaxId" class="form-label"></label>
|
|
<input asp-for="TaxId" class="form-control" />
|
|
<span asp-validation-for="TaxId" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="PaymentTerms" class="form-label"></label>
|
|
<select asp-for="PaymentTerms" class="form-select">
|
|
<option value="">Select payment terms</option>
|
|
<option value="Net 15">Net 15</option>
|
|
<option value="Net 30">Net 30</option>
|
|
<option value="Net 45">Net 45</option>
|
|
<option value="Net 60">Net 60</option>
|
|
<option value="Due on Receipt">Due on Receipt</option>
|
|
<option value="Cash on Delivery">Cash on Delivery</option>
|
|
</select>
|
|
<span asp-validation-for="PaymentTerms" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="CreditLimit" class="form-label"></label>
|
|
<input asp-for="CreditLimit" class="form-control" type="number" step="0.01" />
|
|
<span asp-validation-for="CreditLimit" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label asp-for="PricingTierId" class="form-label"></label>
|
|
<select asp-for="PricingTierId" class="form-select" asp-items="ViewBag.PricingTiers">
|
|
<option value="">-- No Pricing Tier --</option>
|
|
</select>
|
|
<span asp-validation-for="PricingTierId" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="mb-3">
|
|
<label asp-for="Notes" class="form-label"></label>
|
|
<textarea asp-for="Notes" class="form-control" rows="3"></textarea>
|
|
<span asp-validation-for="Notes" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SMS Notifications -->
|
|
<div class="card mb-4 border-info">
|
|
<div class="card-header bg-info bg-opacity-10">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-phone me-2"></i>SMS Notifications
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<input type="hidden" asp-for="ProspectSmsConsentedAt" />
|
|
@if (Model.SmsConsent)
|
|
{
|
|
<div class="alert alert-success alert-permanent mb-3 py-2">
|
|
<i class="bi bi-check-circle me-1"></i>
|
|
<strong>SMS consent was recorded on the quote</strong>
|
|
@if (Model.ProspectSmsConsentedAt.HasValue)
|
|
{
|
|
<span>on @Model.ProspectSmsConsentedAt.Value.ToLocalTime().ToString("MM/dd/yyyy")</span>
|
|
}
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="alert alert-warning alert-permanent mb-3 py-2">
|
|
<i class="bi bi-exclamation-triangle me-1"></i>
|
|
<strong>No SMS consent was recorded on the quote.</strong>
|
|
</div>
|
|
}
|
|
<div class="form-check">
|
|
<input asp-for="SmsConsent" class="form-check-input" id="SmsConsent" />
|
|
<label class="form-check-label fw-semibold" for="SmsConsent">
|
|
Customer has given verbal consent to receive SMS notifications
|
|
</label>
|
|
</div>
|
|
<small class="text-muted d-block mt-1">
|
|
<i class="bi bi-shield-check me-1"></i>
|
|
Only check if the customer has explicitly agreed to receive text messages (TCPA compliance).
|
|
If checked, the new customer record will have SMS enabled and a confirmation text will be sent.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="mb-4">
|
|
<button type="submit" class="btn btn-success btn-lg">
|
|
<i class="bi bi-arrow-right-circle me-1"></i>Convert to Customer
|
|
</button>
|
|
<a asp-action="Details" asp-route-id="@Model.QuoteId" class="btn btn-outline-secondary btn-lg">
|
|
<i class="bi bi-x-circle me-1"></i>Cancel
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Right Column: Help Info -->
|
|
<div class="col-lg-4">
|
|
<div class="card">
|
|
<div class="card-header bg-light">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-info-circle me-2"></i>What Happens Next?
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ol class="mb-0">
|
|
<li class="mb-2">
|
|
<strong>Customer Created:</strong> A new customer record will be created with a unique customer number.
|
|
</li>
|
|
<li class="mb-2">
|
|
<strong>Quote Updated:</strong> The quote will be linked to the new customer and marked as "Converted".
|
|
</li>
|
|
<li class="mb-2">
|
|
<strong>Future Quotes:</strong> You can now create additional quotes for this customer.
|
|
</li>
|
|
<li class="mb-0">
|
|
<strong>Jobs:</strong> You'll be able to convert quotes to jobs for this customer.
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header bg-light">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-lightbulb me-2"></i>Tips
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="mb-0">
|
|
<li class="mb-2">
|
|
Review all contact information carefully before converting.
|
|
</li>
|
|
<li class="mb-2">
|
|
Set an appropriate credit limit if offering credit terms.
|
|
</li>
|
|
<li class="mb-0">
|
|
Assign a pricing tier to give this customer automatic discounts on future quotes.
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
|
<script>
|
|
function toggleCompanyNameRequired() {
|
|
const isCommercial = document.getElementById('IsCommercial').value === 'true';
|
|
const $companyName = $('#CompanyName');
|
|
const $requiredMark = $('#companyNameRequired');
|
|
|
|
if (isCommercial) {
|
|
$requiredMark.show();
|
|
$companyName.rules('add', { required: true, messages: { required: 'Company Name is required for commercial customers.' } });
|
|
} else {
|
|
$requiredMark.hide();
|
|
$companyName.rules('add', { required: false });
|
|
$companyName.valid(); // clear any existing error
|
|
}
|
|
}
|
|
|
|
$(document).ready(function () {
|
|
toggleCompanyNameRequired();
|
|
});
|
|
</script>
|
|
}
|