Sweep all .cshtml files for encoding corruption; add pre-commit guard
Replace all corruption variants with HTML entities across 226 view files: - 3-char UTF-8-as-Win1252 sequences (ae-corruption) - Standalone smart/curly quotes that break C# Razor expressions - Partially re-corrupted variants where the 3rd byte was normalised to ASCII tools/Fix-Encoding.ps1: re-runnable sweep; uses [char] code points so the script itself never contains a literal non-ASCII character; supports -DryRun .githooks/pre-commit: blocks commits containing the ae-corruption byte signature (xc3xa2xe2x82xac); git core.hooksPath = .githooks so the hook is repo-committed and active for all future work on this machine. Build clean; 225 unit tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,10 +22,10 @@
|
||||
<p>
|
||||
Quotes let you provide customers and prospects with a formal price estimate before work begins.
|
||||
The quoting engine calculates material costs, labor, equipment time, overhead, and profit margin
|
||||
automatically based on the surface area and complexity you enter — no spreadsheet required.
|
||||
automatically based on the surface area and complexity you enter — no spreadsheet required.
|
||||
</p>
|
||||
<p>
|
||||
Quotes can be created for existing customers or for <strong>prospects</strong> — people or
|
||||
Quotes can be created for existing customers or for <strong>prospects</strong> — people or
|
||||
businesses who have not yet become customers. Prospect quotes let you capture all contact details
|
||||
and pricing in one place so nothing is lost while you are waiting for a decision. If the prospect
|
||||
accepts, you can convert them to a customer and the quote to a job in just a few clicks.
|
||||
@@ -47,16 +47,16 @@
|
||||
top of the page. Your selection is remembered automatically for next time.
|
||||
</p>
|
||||
<ul class="mb-3">
|
||||
<li class="mb-1"><strong>Quick Quote</strong> — shows only the essentials: customer picker (or walk-in info) and
|
||||
<li class="mb-1"><strong>Quick Quote</strong> — shows only the essentials: customer picker (or walk-in info) and
|
||||
the item wizard. Dates, notes, tags, oven settings, discounts, and photos are hidden. Use this for
|
||||
fast phone or counter estimates where you just need a price.</li>
|
||||
<li class="mb-1"><strong>Full Quote</strong> — shows the complete form with all fields. Use this for formal
|
||||
<li class="mb-1"><strong>Full Quote</strong> — shows the complete form with all fields. Use this for formal
|
||||
quotes where you want to capture notes, set an expiry date, apply a discount, or add photos.</li>
|
||||
</ul>
|
||||
<div class="alert alert-permanent alert-info d-flex gap-2 mb-3" role="alert">
|
||||
<i class="bi bi-lightbulb-fill flex-shrink-0 mt-1"></i>
|
||||
<div>
|
||||
Switching to Quick Quote does not change how the quote saves — all pricing calculations and the item
|
||||
Switching to Quick Quote does not change how the quote saves — all pricing calculations and the item
|
||||
wizard work exactly the same. Hidden fields use their default values (no rush fee, no discount, company
|
||||
default tax rate).
|
||||
</div>
|
||||
@@ -68,13 +68,13 @@
|
||||
<li class="mb-2">
|
||||
Choose whether this quote is for an existing <strong>Customer</strong> or a <strong>Prospect</strong>:
|
||||
<ul class="mt-1">
|
||||
<li><strong>Customer</strong> — select from your existing customer list. The customer's pricing tier discount is applied automatically.</li>
|
||||
<li><strong>Prospect</strong> — enter their first name, last name, company name (optional), email, and phone. These details are stored on the quote and can be used to create a customer record later.</li>
|
||||
<li><strong>Customer</strong> — select from your existing customer list. The customer's pricing tier discount is applied automatically.</li>
|
||||
<li><strong>Prospect</strong> — enter their first name, last name, company name (optional), email, and phone. These details are stored on the quote and can be used to create a customer record later.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="mb-2">Set the <strong>Quote Date</strong> (defaults to today) and the <strong>Expiry Date</strong> (defaults to the system's configured validity period).</li>
|
||||
<li class="mb-2">Add a <strong>Subject</strong> or description to identify the work being quoted.</li>
|
||||
<li class="mb-2">Add one or more <strong>Line Items</strong> — see the Quote Items section below for item types.</li>
|
||||
<li class="mb-2">Add one or more <strong>Line Items</strong> — see the Quote Items section below for item types.</li>
|
||||
<li class="mb-2">Add any <strong>Notes</strong> for the customer (these appear on the printed quote).</li>
|
||||
<li class="mb-2">Add any internal <strong>Notes</strong> that are for your team only.</li>
|
||||
<li class="mb-2">Click <strong>Save Quote</strong>. The quote is saved as a Draft.</li>
|
||||
@@ -125,7 +125,7 @@
|
||||
<div class="card-body small">
|
||||
Enter a free-text description and type a price manually. Use this for one-off work,
|
||||
repairs, or services that do not fit the standard surface-area calculation model.
|
||||
No automatic pricing calculation — you set the price directly.
|
||||
No automatic pricing calculation — you set the price directly.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,10 +154,10 @@
|
||||
<p>
|
||||
If an image has been uploaded for a catalog item, a small thumbnail appears to the left of its
|
||||
name in the list. <strong>Hover over the thumbnail</strong> to see a larger preview near your
|
||||
cursor — useful for quickly confirming you have the right part without opening the full item record.
|
||||
cursor — useful for quickly confirming you have the right part without opening the full item record.
|
||||
</p>
|
||||
<p>
|
||||
Images are managed on the <a href="/CatalogItems">Catalog Items</a> page — open any item, click
|
||||
Images are managed on the <a href="/CatalogItems">Catalog Items</a> page — open any item, click
|
||||
<strong>Edit</strong>, and use the <strong>Item Image</strong> section to upload a photo
|
||||
(jpg, jpeg, png, gif, or webp; max 10 MB). A 200×200 thumbnail is generated automatically.
|
||||
</p>
|
||||
@@ -167,7 +167,7 @@
|
||||
For Calculated and AI Photo items, after entering the surface area you proceed to the coatings
|
||||
step. Select one or more powder coatings from your inventory. The wizard shows how much powder
|
||||
will be needed per coat based on the coverage rate and your surface area. You then choose any
|
||||
prep services — sandblasting, masking, and/or cleaning — that will be performed before coating.
|
||||
prep services — sandblasting, masking, and/or cleaning — that will be performed before coating.
|
||||
</p>
|
||||
|
||||
<h3 class="h6 fw-semibold mt-3 mb-2">Save to Product Catalog</h3>
|
||||
@@ -182,13 +182,13 @@
|
||||
<li>Choose a <strong>Category</strong> from your existing catalog categories.</li>
|
||||
<li>Optionally add or edit a <strong>Description</strong> and flag whether the item typically requires sandblasting or masking.</li>
|
||||
<li>Click <strong>Save to Catalog & Add</strong> to save the item to the catalog and add it to the quote simultaneously.</li>
|
||||
<li>Click <strong>Skip — Add to Quote Only</strong> to add the item to this quote without saving it to the catalog.</li>
|
||||
<li>Click <strong>Skip — Add to Quote Only</strong> to add the item to this quote without saving it to the catalog.</li>
|
||||
</ul>
|
||||
<div class="alert alert-permanent alert-warning d-flex gap-2 mb-3" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill flex-shrink-0 mt-1"></i>
|
||||
<div>
|
||||
<strong>Catalog item prices are final.</strong> When a catalog item is added to a quote or job,
|
||||
the price you entered is used exactly as-is — no markup, no prep service charges, and no
|
||||
the price you entered is used exactly as-is — no markup, no prep service charges, and no
|
||||
complexity adjustments are added on top. Make sure the price you save already includes your
|
||||
labor, materials, and margin.
|
||||
</div>
|
||||
@@ -196,7 +196,7 @@
|
||||
<div class="alert alert-permanent alert-info d-flex gap-2 mb-0" role="alert">
|
||||
<i class="bi bi-bookmark-star-fill flex-shrink-0 mt-1"></i>
|
||||
<div>
|
||||
The catalog save happens <strong>immediately</strong> — the item is added to your catalog even
|
||||
The catalog save happens <strong>immediately</strong> — the item is added to your catalog even
|
||||
if you later abandon the quote. This is intentional: once you take the time to describe and
|
||||
price a part, it's worth keeping for next time. Manage saved items at
|
||||
<a href="/CatalogItems">Catalog Items</a>.
|
||||
@@ -208,7 +208,7 @@
|
||||
<div>
|
||||
The live pricing calculator at the bottom of the quote form updates the subtotal, discounts,
|
||||
tax, and grand total every time you add or change a line item. There is no need to manually
|
||||
recalculate — the total shown when you save is the total the customer will see.
|
||||
recalculate — the total shown when you save is the total the customer will see.
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -292,7 +292,7 @@
|
||||
</p>
|
||||
<ul class="mb-3">
|
||||
<li class="mb-1">The customer must have <strong>SMS Opt-In</strong> enabled and a <strong>Mobile Phone</strong> number on their record.</li>
|
||||
<li class="mb-1">If you already sent the quote via email, the same approval link is reused — both the email link and SMS link remain valid simultaneously.</li>
|
||||
<li class="mb-1">If you already sent the quote via email, the same approval link is reused — both the email link and SMS link remain valid simultaneously.</li>
|
||||
<li class="mb-1">For prospect quotes, the SMS goes to the <strong>Prospect Phone</strong> field on the quote.</li>
|
||||
</ul>
|
||||
<p>
|
||||
@@ -369,7 +369,7 @@
|
||||
</h2>
|
||||
<p>
|
||||
When you send a quote by email, the customer receives a link to a self-service approval portal
|
||||
at <strong>/QuoteApproval</strong>. No login is required — the link is unique to that quote.
|
||||
at <strong>/QuoteApproval</strong>. No login is required — the link is unique to that quote.
|
||||
</p>
|
||||
<p>From the approval portal the customer can:</p>
|
||||
<ul class="mb-3">
|
||||
@@ -410,7 +410,7 @@
|
||||
</h2>
|
||||
<p>
|
||||
The <strong>AI Quick Quote</strong> widget lets you get an instant rough estimate from a verbal
|
||||
description — perfect for phone calls and walk-in customers when you don't have time to open the
|
||||
description — perfect for phone calls and walk-in customers when you don't have time to open the
|
||||
full quoting wizard. Look for the dark-blue floating button in the bottom-right corner of any page,
|
||||
just above the AI Help button.
|
||||
</p>
|
||||
@@ -419,13 +419,13 @@
|
||||
<ol class="mb-3">
|
||||
<li class="mb-2">Click the <strong>AI Quick Quote</strong> floating button (bottom-right, dark blue with a lightning bolt icon).</li>
|
||||
<li class="mb-2">
|
||||
Type a description of the work — for example:<br>
|
||||
Type a description of the work — for example:<br>
|
||||
<em>"4 motorcycle wheels in Alien Silver with a black base coat, need sandblasting"</em>
|
||||
</li>
|
||||
<li class="mb-2">Set the <strong>Quantity</strong> and <strong>Number of Coats</strong>.</li>
|
||||
<li class="mb-2">Click <strong>Get Estimate</strong>. The AI analyses your description and returns a price estimate, estimated minutes, surface area, complexity rating, and a confidence score in just a few seconds.</li>
|
||||
<li class="mb-2">
|
||||
The panel also shows <strong>powder stock status</strong> for any color names detected in your description — a green check means you have it in stock, red means you don't, and a grey question mark means the system couldn't match it.
|
||||
The panel also shows <strong>powder stock status</strong> for any color names detected in your description — a green check means you have it in stock, red means you don't, and a grey question mark means the system couldn't match it.
|
||||
</li>
|
||||
<li class="mb-2">If the estimate looks right, enter an optional <strong>Customer Reference</strong> (e.g., the caller's name) and click <strong>Save as Draft Quote</strong>. You land directly on the new quote's Details page where you can adjust anything and assign the real customer.</li>
|
||||
</ol>
|
||||
@@ -433,13 +433,13 @@
|
||||
<div class="alert alert-permanent alert-info d-flex gap-2 mb-3" role="alert">
|
||||
<i class="bi bi-lightbulb-fill flex-shrink-0 mt-1"></i>
|
||||
<div>
|
||||
Quick quotes are saved under a <strong>"Walk-In / Phone"</strong> customer so nothing blocks you from saving immediately. Once you have the customer's information, reassign the quote using the Customer dropdown on the Quote Details page — see <em>Changing the Customer</em> below.
|
||||
Quick quotes are saved under a <strong>"Walk-In / Phone"</strong> customer so nothing blocks you from saving immediately. Once you have the customer's information, reassign the quote using the Customer dropdown on the Quote Details page — see <em>Changing the Customer</em> below.
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-permanent alert-warning d-flex gap-2 mb-0" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill flex-shrink-0 mt-1"></i>
|
||||
<div>
|
||||
The Quick Quote gives a rough estimate only — it uses your shop's operating costs and the AI's
|
||||
The Quick Quote gives a rough estimate only — it uses your shop's operating costs and the AI's
|
||||
interpretation of your description. For formal quotes that will be sent to a customer, always
|
||||
open the quote and verify the details using the full item wizard before sending.
|
||||
</div>
|
||||
@@ -451,7 +451,7 @@
|
||||
<i class="bi bi-person-gear text-primary me-2"></i>Changing the Customer
|
||||
</h2>
|
||||
<p>
|
||||
The customer on a quote can be changed at any time from the Quote Details page — no need to
|
||||
The customer on a quote can be changed at any time from the Quote Details page — no need to
|
||||
delete and re-create the quote. This is particularly useful when:
|
||||
</p>
|
||||
<ul class="mb-3">
|
||||
@@ -463,9 +463,9 @@
|
||||
<h3 class="h6 fw-semibold mt-3 mb-2">How to change the customer</h3>
|
||||
<ol class="mb-3">
|
||||
<li class="mb-2">Open the quote from <strong>Operations › Quotes</strong> and go to its Details page.</li>
|
||||
<li class="mb-2">Find the <strong>Customer</strong> field in the quote header — it appears as a dropdown showing the current customer.</li>
|
||||
<li class="mb-2">Find the <strong>Customer</strong> field in the quote header — it appears as a dropdown showing the current customer.</li>
|
||||
<li class="mb-2">Select a different customer from the dropdown.</li>
|
||||
<li class="mb-2">A confirmation banner appears: <em>"Change customer to [Name]?"</em> — click <strong>Save</strong> to confirm or <strong>Cancel</strong> to revert to the original.</li>
|
||||
<li class="mb-2">A confirmation banner appears: <em>"Change customer to [Name]?"</em> — click <strong>Save</strong> to confirm or <strong>Cancel</strong> to revert to the original.</li>
|
||||
</ol>
|
||||
<div class="alert alert-permanent alert-info d-flex gap-2 mb-0" role="alert">
|
||||
<i class="bi bi-info-circle flex-shrink-0 mt-1"></i>
|
||||
@@ -487,22 +487,22 @@
|
||||
whether your rates are covering costs. The breakdown includes:
|
||||
</p>
|
||||
<ul class="mb-3">
|
||||
<li class="mb-1"><strong>Material Costs</strong> — powder and consumables cost based on surface area and the configured cost-per-sq-ft rate.</li>
|
||||
<li class="mb-1"><strong>Shop Supplies</strong> — a small percentage of material and labor costs covering miscellaneous shop consumables (tape, abrasives, etc.).</li>
|
||||
<li class="mb-1"><strong>Labor Costs</strong> — base labor calculated from estimated job minutes. Sandblasting prep is charged at 1.5× the standard labor rate; masking at 0.5×. Additional coats beyond the first are charged at the configured additional coat labor percentage.</li>
|
||||
<li class="mb-1"><strong>Equipment Costs</strong> — hourly rates for the curing oven, sandblaster, and coating booth, applied for the estimated time each piece of equipment is in use.</li>
|
||||
<li class="mb-1"><strong>Complexity Adjustment</strong> — a percentage added based on the item's complexity rating (Simple, Moderate, Complex, or Extreme). Simple items have no adjustment; Extreme items can add 25% or more.</li>
|
||||
<li class="mb-1"><strong>General Markup</strong> — your configured profit percentage applied to the cost subtotal. The exact formula depends on the <em>Pricing Mode</em> set in Company Settings: <em>Markup on Materials</em> adds the percentage on top of costs; <em>Target Margin on Total Cost</em> back-calculates price from a gross-margin target.</li>
|
||||
<li class="mb-1"><strong>Rush Charge</strong> — applied automatically to jobs with Rush or Urgent priority, either as a percentage or a fixed amount depending on your settings.</li>
|
||||
<li class="mb-1"><strong>Pricing Tier Discount</strong> — if the customer has a pricing tier assigned (e.g., Preferred Shop — 10% off), the discount is shown as a line item reduction. See <em>Hide Discount from Customer</em> below to control whether this line appears on the customer-facing PDF.</li>
|
||||
<li class="mb-1"><strong>Tax</strong> — the configured tax rate applied to the final subtotal. Zero for tax-exempt customers.</li>
|
||||
<li class="mb-1"><strong>Grand Total</strong> — the amount the customer will be invoiced.</li>
|
||||
<li class="mb-1"><strong>Material Costs</strong> — powder and consumables cost based on surface area and the configured cost-per-sq-ft rate.</li>
|
||||
<li class="mb-1"><strong>Shop Supplies</strong> — a small percentage of material and labor costs covering miscellaneous shop consumables (tape, abrasives, etc.).</li>
|
||||
<li class="mb-1"><strong>Labor Costs</strong> — base labor calculated from estimated job minutes. Sandblasting prep is charged at 1.5× the standard labor rate; masking at 0.5×. Additional coats beyond the first are charged at the configured additional coat labor percentage.</li>
|
||||
<li class="mb-1"><strong>Equipment Costs</strong> — hourly rates for the curing oven, sandblaster, and coating booth, applied for the estimated time each piece of equipment is in use.</li>
|
||||
<li class="mb-1"><strong>Complexity Adjustment</strong> — a percentage added based on the item's complexity rating (Simple, Moderate, Complex, or Extreme). Simple items have no adjustment; Extreme items can add 25% or more.</li>
|
||||
<li class="mb-1"><strong>General Markup</strong> — your configured profit percentage applied to the cost subtotal. The exact formula depends on the <em>Pricing Mode</em> set in Company Settings: <em>Markup on Materials</em> adds the percentage on top of costs; <em>Target Margin on Total Cost</em> back-calculates price from a gross-margin target.</li>
|
||||
<li class="mb-1"><strong>Rush Charge</strong> — applied automatically to jobs with Rush or Urgent priority, either as a percentage or a fixed amount depending on your settings.</li>
|
||||
<li class="mb-1"><strong>Pricing Tier Discount</strong> — if the customer has a pricing tier assigned (e.g., Preferred Shop — 10% off), the discount is shown as a line item reduction. See <em>Hide Discount from Customer</em> below to control whether this line appears on the customer-facing PDF.</li>
|
||||
<li class="mb-1"><strong>Tax</strong> — the configured tax rate applied to the final subtotal. Zero for tax-exempt customers.</li>
|
||||
<li class="mb-1"><strong>Grand Total</strong> — the amount the customer will be invoiced.</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="h6 fw-semibold mt-4 mb-2">Per-Item Cost Breakdown</h3>
|
||||
<p>
|
||||
Each line item on the Quote Details page can be expanded to show a cost breakdown for that
|
||||
individual item — click the row to open it. The per-item breakdown shows how material, labor,
|
||||
individual item — click the row to open it. The per-item breakdown shows how material, labor,
|
||||
equipment, complexity, and markup were calculated for that specific piece. This is useful for
|
||||
spotting underpriced items or understanding where costs are concentrated across a multi-item quote.
|
||||
</p>
|
||||
@@ -514,7 +514,7 @@
|
||||
</p>
|
||||
<ul class="mb-3">
|
||||
<li class="mb-1">The pricing tier discount line is <strong>not shown</strong> on the customer-facing quote PDF or on the online approval portal.</li>
|
||||
<li class="mb-1">The discount is <strong>still applied</strong> to the total — the customer pays the discounted price, they just don’t see the discount as a separate line item.</li>
|
||||
<li class="mb-1">The discount is <strong>still applied</strong> to the total — the customer pays the discounted price, they just don’t see the discount as a separate line item.</li>
|
||||
<li class="mb-1">The full breakdown (including the discount) remains visible to your staff on the internal Quote Details page.</li>
|
||||
</ul>
|
||||
<p>
|
||||
@@ -525,8 +525,8 @@
|
||||
<div class="alert alert-permanent alert-secondary d-flex gap-2 mb-0" role="alert">
|
||||
<i class="bi bi-info-circle flex-shrink-0 mt-1"></i>
|
||||
<div>
|
||||
All rates used in the breakdown — labor, equipment, markup, shop supplies, complexity multipliers,
|
||||
rush charge, and tax — are configured in <strong>Settings › Company Settings › Operating Costs</strong>.
|
||||
All rates used in the breakdown — labor, equipment, markup, shop supplies, complexity multipliers,
|
||||
rush charge, and tax — are configured in <strong>Settings › Company Settings › Operating Costs</strong>.
|
||||
See the <a asp-controller="Help" asp-action="Settings">Settings help page</a> for details on Pricing Mode and all rate settings.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user