Initial commit
This commit is contained in:
@@ -0,0 +1,439 @@
|
||||
@model PowderCoating.Application.DTOs.Customer.UpdateCustomerDto
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit Customer";
|
||||
ViewData["PageIcon"] = "bi-pencil-square";
|
||||
}
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="d-flex justify-content-end align-items-center mb-4">
|
||||
<a asp-action="Index" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to List
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
<form asp-action="Edit" method="post">
|
||||
<input type="hidden" asp-for="Id" />
|
||||
<partial name="_ValidationSummary" />
|
||||
|
||||
<!-- Company Information Section -->
|
||||
<div class="mb-4">
|
||||
<div class="d-flex align-items-center gap-2 border-bottom pb-2 mb-3">
|
||||
<h5 class="mb-0"><i class="bi bi-building me-2 text-primary"></i>Company Information</h5>
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Company Information"
|
||||
data-bs-content="Company Name is used on quotes, invoices, and correspondence. Customer Type controls which features are available — Commercial customers get payment terms, credit limits, and pricing tier discounts. Status Inactive hides the customer from new quote/job dropdowns but preserves all history.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label asp-for="CompanyName" class="form-label">Company Name</label>
|
||||
<input asp-for="CompanyName" class="form-control" placeholder="Enter company name" />
|
||||
<span asp-validation-for="CompanyName" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="IsCommercial" class="form-label">Customer Type
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Customer Type"
|
||||
data-bs-content="Commercial: businesses with ongoing work, purchase orders, and invoicing. Individual: walk-in customers or one-off jobs. This affects which fields are shown and whether pricing tier discounts apply.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</label>
|
||||
<select asp-for="IsCommercial" class="form-select">
|
||||
<option value="false">Individual</option>
|
||||
<option value="true">Commercial</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="IsActive" class="form-label">Status</label>
|
||||
<select asp-for="IsActive" class="form-select">
|
||||
<option value="true">Active</option>
|
||||
<option value="false">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact Information Section -->
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
<i class="bi bi-person me-2 text-primary"></i>Contact Information
|
||||
</h5>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label asp-for="ContactFirstName" class="form-label">First Name</label>
|
||||
<input asp-for="ContactFirstName" class="form-control" placeholder="Enter first name" />
|
||||
<span asp-validation-for="ContactFirstName" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label asp-for="ContactLastName" class="form-label">Last Name</label>
|
||||
<input asp-for="ContactLastName" class="form-control" placeholder="Enter last name" />
|
||||
<span asp-validation-for="ContactLastName" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label asp-for="Email" class="form-label">Email</label>
|
||||
<input asp-for="Email" type="email" class="form-control" placeholder="name@example.com" />
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="Phone" class="form-label">Phone</label>
|
||||
<input asp-for="Phone" type="tel" class="form-control" placeholder="(555) 123-4567" />
|
||||
<span asp-validation-for="Phone" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="MobilePhone" class="form-label">Mobile Phone</label>
|
||||
<input asp-for="MobilePhone" type="tel" class="form-control" placeholder="(555) 123-4567" />
|
||||
<span asp-validation-for="MobilePhone" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Address Section -->
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
<i class="bi bi-geo-alt me-2 text-primary"></i>Address
|
||||
</h5>
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<label asp-for="Address" class="form-label">Street Address</label>
|
||||
<input asp-for="Address" class="form-control" placeholder="Enter street address" />
|
||||
<span asp-validation-for="Address" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<label asp-for="City" class="form-label">City</label>
|
||||
<input asp-for="City" class="form-control" placeholder="Enter city" />
|
||||
<span asp-validation-for="City" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="State" class="form-label">State</label>
|
||||
<input asp-for="State" class="form-control" placeholder="Enter state" />
|
||||
<span asp-validation-for="State" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label asp-for="ZipCode" class="form-label">Zip Code</label>
|
||||
<input asp-for="ZipCode" class="form-control" placeholder="12345" />
|
||||
<span asp-validation-for="ZipCode" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label asp-for="Country" class="form-label">Country</label>
|
||||
<select asp-for="Country" class="form-select">
|
||||
<option value="">-- Select --</option>
|
||||
<option value="USA">USA</option>
|
||||
<option value="Canada">Canada</option>
|
||||
<option value="Mexico">Mexico</option>
|
||||
<option value="Afghanistan">Afghanistan</option>
|
||||
<option value="Albania">Albania</option>
|
||||
<option value="Algeria">Algeria</option>
|
||||
<option value="Argentina">Argentina</option>
|
||||
<option value="Australia">Australia</option>
|
||||
<option value="Austria">Austria</option>
|
||||
<option value="Bangladesh">Bangladesh</option>
|
||||
<option value="Belgium">Belgium</option>
|
||||
<option value="Bolivia">Bolivia</option>
|
||||
<option value="Brazil">Brazil</option>
|
||||
<option value="Chile">Chile</option>
|
||||
<option value="China">China</option>
|
||||
<option value="Colombia">Colombia</option>
|
||||
<option value="Costa Rica">Costa Rica</option>
|
||||
<option value="Croatia">Croatia</option>
|
||||
<option value="Czech Republic">Czech Republic</option>
|
||||
<option value="Denmark">Denmark</option>
|
||||
<option value="Dominican Republic">Dominican Republic</option>
|
||||
<option value="Ecuador">Ecuador</option>
|
||||
<option value="Egypt">Egypt</option>
|
||||
<option value="El Salvador">El Salvador</option>
|
||||
<option value="Finland">Finland</option>
|
||||
<option value="France">France</option>
|
||||
<option value="Germany">Germany</option>
|
||||
<option value="Ghana">Ghana</option>
|
||||
<option value="Greece">Greece</option>
|
||||
<option value="Guatemala">Guatemala</option>
|
||||
<option value="Honduras">Honduras</option>
|
||||
<option value="Hungary">Hungary</option>
|
||||
<option value="India">India</option>
|
||||
<option value="Indonesia">Indonesia</option>
|
||||
<option value="Iran">Iran</option>
|
||||
<option value="Iraq">Iraq</option>
|
||||
<option value="Ireland">Ireland</option>
|
||||
<option value="Israel">Israel</option>
|
||||
<option value="Italy">Italy</option>
|
||||
<option value="Japan">Japan</option>
|
||||
<option value="Jordan">Jordan</option>
|
||||
<option value="Kazakhstan">Kazakhstan</option>
|
||||
<option value="Kenya">Kenya</option>
|
||||
<option value="South Korea">South Korea</option>
|
||||
<option value="Kuwait">Kuwait</option>
|
||||
<option value="Malaysia">Malaysia</option>
|
||||
<option value="Netherlands">Netherlands</option>
|
||||
<option value="New Zealand">New Zealand</option>
|
||||
<option value="Nicaragua">Nicaragua</option>
|
||||
<option value="Nigeria">Nigeria</option>
|
||||
<option value="Norway">Norway</option>
|
||||
<option value="Pakistan">Pakistan</option>
|
||||
<option value="Panama">Panama</option>
|
||||
<option value="Paraguay">Paraguay</option>
|
||||
<option value="Peru">Peru</option>
|
||||
<option value="Philippines">Philippines</option>
|
||||
<option value="Poland">Poland</option>
|
||||
<option value="Portugal">Portugal</option>
|
||||
<option value="Puerto Rico">Puerto Rico</option>
|
||||
<option value="Romania">Romania</option>
|
||||
<option value="Russia">Russia</option>
|
||||
<option value="Saudi Arabia">Saudi Arabia</option>
|
||||
<option value="South Africa">South Africa</option>
|
||||
<option value="Spain">Spain</option>
|
||||
<option value="Sweden">Sweden</option>
|
||||
<option value="Switzerland">Switzerland</option>
|
||||
<option value="Taiwan">Taiwan</option>
|
||||
<option value="Thailand">Thailand</option>
|
||||
<option value="Turkey">Turkey</option>
|
||||
<option value="Ukraine">Ukraine</option>
|
||||
<option value="United Arab Emirates">United Arab Emirates</option>
|
||||
<option value="United Kingdom">United Kingdom</option>
|
||||
<option value="Uruguay">Uruguay</option>
|
||||
<option value="Venezuela">Venezuela</option>
|
||||
<option value="Vietnam">Vietnam</option>
|
||||
</select>
|
||||
<span asp-validation-for="Country" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Business Information Section -->
|
||||
<div class="mb-4">
|
||||
<div class="d-flex align-items-center gap-2 border-bottom pb-2 mb-3">
|
||||
<h5 class="mb-0"><i class="bi bi-briefcase me-2 text-primary"></i>Business Information</h5>
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Business Information"
|
||||
data-bs-content="Payment Terms sets the default due date on invoices (e.g., Net 30 = 30 days from invoice date). Credit Limit is a soft warning cap — the system alerts when exceeded. Tax Exempt removes tax from all invoices; upload the exemption certificate in the Tax Exempt Certificate section below.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label asp-for="TaxId" class="form-label">Tax ID / EIN</label>
|
||||
<input asp-for="TaxId" class="form-control" placeholder="Enter tax ID" />
|
||||
<span asp-validation-for="TaxId" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label asp-for="PaymentTerms" class="form-label">Payment Terms</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 class="col-md-3">
|
||||
<label asp-for="PricingTierId" class="form-label">Pricing Tier</label>
|
||||
<select asp-for="PricingTierId" asp-items="ViewBag.PricingTiers" class="form-select">
|
||||
<option value="">— No tier —</option>
|
||||
</select>
|
||||
<small class="text-muted">Applies a discount to all quotes for this customer.</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label asp-for="CreditLimit" class="form-label">Credit Limit</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input asp-for="CreditLimit" type="number" step="0.01" min="0" class="form-control" placeholder="0.00" />
|
||||
</div>
|
||||
<span asp-validation-for="CreditLimit" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3 mt-2">
|
||||
<div class="col-md-6">
|
||||
<div class="form-check form-switch">
|
||||
<input asp-for="IsTaxExempt" class="form-check-input" type="checkbox" />
|
||||
<label asp-for="IsTaxExempt" class="form-check-label">Tax Exempt Customer</label>
|
||||
</div>
|
||||
<small class="text-muted">Check this box if the customer is tax exempt</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notes Section -->
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
<i class="bi bi-journal-text me-2 text-primary"></i>Notes
|
||||
</h5>
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<label asp-for="GeneralNotes" class="form-label">General Notes</label>
|
||||
<textarea asp-for="GeneralNotes" class="form-control" rows="4" placeholder="Enter any additional notes about this customer"></textarea>
|
||||
<span asp-validation-for="GeneralNotes" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification Preferences -->
|
||||
<div class="mb-4">
|
||||
<div class="d-flex align-items-center gap-2 border-bottom pb-2 mb-3">
|
||||
<h5 class="mb-0"><i class="bi bi-bell me-2 text-primary"></i>Notification Preferences</h5>
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Notification Preferences"
|
||||
data-bs-content="Controls when the customer receives automatic updates. Email notifications send status change alerts (e.g., job ready for pickup) to the customer's email address. SMS requires separate TCPA consent — uncheck 'SMS Notifications Active' to temporarily pause without revoking consent.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<!-- Email -->
|
||||
<div class="col-md-6">
|
||||
<div class="form-check form-switch">
|
||||
<input asp-for="NotifyByEmail" class="form-check-input" type="checkbox" role="switch" />
|
||||
<label asp-for="NotifyByEmail" class="form-check-label">
|
||||
<i class="bi bi-envelope me-1"></i>Email Notifications
|
||||
</label>
|
||||
<div class="form-text">Receive quote and job status updates by email.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (ViewBag.SmsEnabled == true)
|
||||
{
|
||||
<!-- SMS: show consent status or consent capture depending on existing consent -->
|
||||
<div class="mt-3">
|
||||
@if (Model.SmsConsentedAt.HasValue)
|
||||
{
|
||||
<!-- Consent already recorded — show status and allow pause/resume -->
|
||||
<div class="card border-success bg-success-subtle p-3 mb-2">
|
||||
<div class="d-flex align-items-start gap-3">
|
||||
<i class="bi bi-shield-fill-check text-success fs-4 mt-1"></i>
|
||||
<div class="flex-fill">
|
||||
<div class="fw-semibold text-success mb-1">SMS Consent Recorded</div>
|
||||
<div class="small text-body-secondary">
|
||||
Consent method: <strong>@Model.SmsConsentMethod</strong><br />
|
||||
Recorded: <strong>@Model.SmsConsentedAt.Value.Tz(ViewBag.CompanyTimeZone as string).ToString("MMMM d, yyyy 'at' h:mm tt")</strong>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<div class="form-check form-switch">
|
||||
<input asp-for="NotifyBySms" class="form-check-input" type="checkbox" role="switch" />
|
||||
<label asp-for="NotifyBySms" class="form-check-label">
|
||||
<i class="bi bi-phone me-1"></i>SMS Notifications Active
|
||||
</label>
|
||||
<div class="form-text">Uncheck to temporarily pause SMS without revoking consent.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- No consent on file — show the compliance notice and consent checkbox -->
|
||||
<div class="alert alert-warning border-warning alert-permanent" role="alert">
|
||||
<h6 class="alert-heading fw-bold mb-2">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>SMS Consent Requirement (TCPA)
|
||||
</h6>
|
||||
<p class="mb-2">
|
||||
Federal law (TCPA) requires <strong>explicit prior verbal or written consent</strong> before sending SMS messages.
|
||||
Before enabling SMS notifications, you must:
|
||||
</p>
|
||||
<ol class="mb-2 ps-3">
|
||||
<li>Inform the customer they will receive automated texts for job updates and pickup alerts.</li>
|
||||
<li>Inform them that message and data rates may apply.</li>
|
||||
<li>Explain they can reply <strong>STOP</strong> at any time to opt out.</li>
|
||||
<li>Obtain their clear verbal or written agreement.</li>
|
||||
</ol>
|
||||
<p class="mb-0 small text-muted">
|
||||
Only check the box below <strong>after</strong> the customer has given consent.
|
||||
A confirmation text will be sent automatically to verify enrollment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="card border-secondary bg-body-secondary p-3">
|
||||
<div class="form-check">
|
||||
<input asp-for="SmsConsentGranted" class="form-check-input" type="checkbox" id="SmsConsentGranted" />
|
||||
<label class="form-check-label fw-semibold" for="SmsConsentGranted">
|
||||
<i class="bi bi-shield-check me-1 text-success"></i>
|
||||
Customer has verbally consented to receive SMS notifications
|
||||
</label>
|
||||
<div class="form-text">
|
||||
Checking this box records consent on behalf of the customer and triggers a confirmation text.
|
||||
A mobile phone number must be entered above.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Form Actions -->
|
||||
<div class="d-flex gap-2 justify-content-end pt-3 border-top">
|
||||
<a asp-action="Index" class="btn btn-outline-secondary px-4">Cancel</a>
|
||||
<button type="submit" class="btn btn-primary px-4">
|
||||
<i class="bi bi-save me-2"></i>Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tax Exempt Certificate Section (Outside main form) -->
|
||||
<div class="card border-0 shadow-sm mt-4">
|
||||
<div class="card-body p-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
<i class="bi bi-file-earmark-check me-2 text-primary"></i>Tax Exempt Certificate
|
||||
</h5>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
@if (Model.HasTaxExemptCertificate)
|
||||
{
|
||||
<div class="alert alert-success d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<i class="bi bi-file-earmark-check me-2"></i>
|
||||
<strong>Certificate on file:</strong> @Model.TaxExemptCertificateFileName
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<a asp-action="TaxExemptCertificate" asp-route-id="@Model.Id" class="btn btn-sm btn-outline-primary" target="_blank">
|
||||
<i class="bi bi-download"></i> Download
|
||||
</a>
|
||||
<form asp-action="DeleteTaxExemptCertificate" asp-route-id="@Model.Id" method="post" style="display:inline;"
|
||||
onsubmit="return confirm('Are you sure you want to delete this certificate?');">
|
||||
@Html.AntiForgeryToken()
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger">
|
||||
<i class="bi bi-trash"></i> Delete
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="text-muted">No tax exempt certificate on file.</p>
|
||||
}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<form asp-action="UploadTaxExemptCertificate" asp-route-id="@Model.Id" method="post" enctype="multipart/form-data">
|
||||
@Html.AntiForgeryToken()
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Upload New Certificate</label>
|
||||
<input type="file" name="certificateFile" class="form-control" accept=".pdf,.jpg,.jpeg,.png" />
|
||||
<small class="text-muted">Accepted formats: PDF, JPG, PNG (Max 10 MB)</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-upload"></i> Upload Certificate
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
||||
Reference in New Issue
Block a user