Add CRM features: Additional Contacts, Lead Source, Ship-To Address; update Help docs

- New CustomerContact entity + migration (AddCustomerContactsAndCrmFields)
- Customer.LeadSource + ShipToAddress/City/State/ZipCode/Country fields
- Additional Contacts card on Customer Details with AJAX add/edit/delete
- Lead Source dropdown on Create/Edit; Ship-To section on Create/Edit
- Customer Details: side-by-side billing/ship-to when ship-to is set
- Help docs: Customers (contacts, ship-to, lead source, preferred powders, outstanding pickups)
- Help docs: Jobs (clone job, project name), Quotes (project name), Invoices (project name), Inventory (low stock clickable filter)
- HelpKnowledgeBase.cs updated for all features above

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 12:46:08 -04:00
parent 711cd01cd3
commit 94a89ee175
22 changed files with 12586 additions and 31 deletions
@@ -213,6 +213,42 @@
</div>
</div>
<!-- Ship-To Address 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-truck me-2 text-primary"></i>Ship-To / Pickup Address</h5>
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="Ship-To Address"
data-bs-content="Optional. Fill in only if this customer picks up or receives deliveries at a different address than their billing address. Leave blank to use the billing address above.">
<i class="bi bi-question-circle"></i>
</a>
<span class="text-muted small fw-normal">(optional &mdash; leave blank if same as billing)</span>
</div>
<div class="row g-3">
<div class="col-12">
<label asp-for="ShipToAddress" class="form-label">Street Address</label>
<input asp-for="ShipToAddress" class="form-control" placeholder="Enter ship-to street address" />
</div>
<div class="col-md-5">
<label asp-for="ShipToCity" class="form-label">City</label>
<input asp-for="ShipToCity" class="form-control" placeholder="Enter city" />
</div>
<div class="col-md-3">
<label asp-for="ShipToState" class="form-label">State</label>
<input asp-for="ShipToState" class="form-control" placeholder="Enter state" />
</div>
<div class="col-md-2">
<label asp-for="ShipToZipCode" class="form-label">Zip Code</label>
<input asp-for="ShipToZipCode" class="form-control" placeholder="12345" />
</div>
<div class="col-md-2">
<label asp-for="ShipToCountry" class="form-label">Country</label>
<input asp-for="ShipToCountry" class="form-control" placeholder="USA" />
</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">
@@ -270,6 +306,30 @@
</div>
</div>
<!-- Lead Source Section -->
<div class="mb-4">
<h5 class="border-bottom pb-2 mb-3">
<i class="bi bi-signpost me-2 text-primary"></i>How Did They Find Us?
</h5>
<div class="row g-3">
<div class="col-md-6">
<label asp-for="LeadSource" class="form-label">Lead Source</label>
<select asp-for="LeadSource" class="form-select">
<option value="">&mdash; Not specified &mdash;</option>
<option value="Walk-In">Walk-In</option>
<option value="Google Search">Google Search</option>
<option value="Customer Referral">Customer Referral</option>
<option value="Social Media">Social Media</option>
<option value="Website">Website</option>
<option value="Repeat Customer">Repeat Customer</option>
<option value="Trade Show / Event">Trade Show / Event</option>
<option value="Flyer / Print Ad">Flyer / Print Ad</option>
<option value="Other">Other</option>
</select>
</div>
</div>
</div>
<!-- Notes Section -->
<div class="mb-4">
<h5 class="border-bottom pb-2 mb-3">