Allow fractional quantities (< 1) in item wizard
Catalog, calculated, generic, formula, and AI item types now accept decimal quantities (e.g. 0.25 for a quarter of a catalog set). Sales/ merchandise items remain whole-number only. - Input min changed from 1 to 0.01; step="0.01" added where missing - All parseInt reads on quantity inputs changed to parseFloat so values like 0.25 aren't truncated to 0 before being stored in wz.data - Server-side Quantity is already decimal on all relevant DTOs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -435,7 +435,7 @@ function renderProductFields() {
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label fw-semibold">Quantity <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" id="wz_quantity" min="1" value="1">
|
||||
<input type="number" class="form-control" id="wz_quantity" min="0.01" step="0.01" value="1">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label fw-semibold">Price Override <small class="text-muted">($/unit, optional)</small></label>
|
||||
@@ -526,7 +526,7 @@ function renderCalculatedFields() {
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label fw-semibold">Quantity <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" id="wz_quantity" min="1" value="1">
|
||||
<input type="number" class="form-control" id="wz_quantity" min="0.01" step="0.01" value="1">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label fw-semibold">${escHtml(areaUnit)} per item <span class="text-danger">*</span></label>
|
||||
@@ -615,7 +615,7 @@ function renderGenericFields() {
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label fw-semibold">Quantity <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" id="wz_quantity" min="1" value="1">
|
||||
<input type="number" class="form-control" id="wz_quantity" min="0.01" step="0.01" value="1">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label fw-semibold">Unit Price <span class="text-danger">*</span></label>
|
||||
@@ -932,7 +932,7 @@ function renderFormulaFields() {
|
||||
<div class="mb-2 row g-2">
|
||||
<div class="col-4">
|
||||
<label class="form-label">Quantity</label>
|
||||
<input type="number" id="wz_formula_qty" class="form-control" value="${wz.data.quantity || 1}" min="1" />
|
||||
<input type="number" id="wz_formula_qty" class="form-control" value="${wz.data.quantity || 1}" min="0.01" step="0.01" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="wz_formula_fields">${fieldsHtml}</div>
|
||||
@@ -1058,7 +1058,7 @@ function renderAiPhotoFields() {
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label fw-semibold">Quantity <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" id="ai_quantity" min="1" value="${wz.data.quantity || 1}">
|
||||
<input type="number" class="form-control" id="ai_quantity" min="0.01" step="0.01" value="${wz.data.quantity || 1}">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label fw-semibold">Desired Color / Finish</label>
|
||||
@@ -1490,7 +1490,7 @@ async function aiAnalyze() {
|
||||
}
|
||||
document.getElementById('ai_dimError')?.classList.add('d-none');
|
||||
|
||||
const qty = parseInt(document.getElementById('ai_quantity')?.value) || 1;
|
||||
const qty = parseFloat(document.getElementById('ai_quantity')?.value) || 1;
|
||||
const color = document.getElementById('ai_color')?.value?.trim() || '';
|
||||
const coats = parseInt(document.getElementById('ai_coatCount')?.value) || 1;
|
||||
const materialType = document.getElementById('ai_materialType')?.value?.trim() || '';
|
||||
@@ -1584,7 +1584,7 @@ async function aiSendFollowup() {
|
||||
aiSetLoading(true);
|
||||
document.getElementById('ai_followupSection')?.classList.add('d-none');
|
||||
|
||||
const qty = parseInt(document.getElementById('ai_quantity')?.value) || 1;
|
||||
const qty = parseFloat(document.getElementById('ai_quantity')?.value) || 1;
|
||||
const color = document.getElementById('ai_color')?.value?.trim() || '';
|
||||
const coats = parseInt(document.getElementById('ai_coatCount')?.value) || 1;
|
||||
const ref = document.getElementById('ai_referenceDim')?.value?.trim() || '';
|
||||
@@ -2429,7 +2429,7 @@ function onPowderSelected(i) {
|
||||
|
||||
function updatePowderNeeded(i) {
|
||||
const sqft = parseFloat(wz.data.surfaceAreaSqFt) || 0;
|
||||
const qty = parseInt(wz.data.quantity) || 1;
|
||||
const qty = parseFloat(wz.data.quantity) || 1;
|
||||
if (sqft <= 0) return; // only meaningful for calculated items with surface area
|
||||
|
||||
const isCustom = document.getElementById(`coat_custom_${i}`)?.checked;
|
||||
@@ -2628,7 +2628,7 @@ function collectStep2() {
|
||||
wz.data.surfaceAreaSqFt = cat ? (parseFloat(cat.approxArea) || 0) : 0;
|
||||
wz.data.estimatedMinutes = cat ? (parseInt(cat.defaultMinutes) || 0) : 0;
|
||||
}
|
||||
wz.data.quantity = parseInt(document.getElementById('wz_quantity')?.value) || 1;
|
||||
wz.data.quantity = parseFloat(document.getElementById('wz_quantity')?.value) || 1;
|
||||
const override = parseFloat(document.getElementById('wz_powderCostOverride')?.value);
|
||||
wz.data.powderCostOverride = isNaN(override) ? null : override;
|
||||
}
|
||||
@@ -2654,7 +2654,7 @@ function collectStep2() {
|
||||
wz.data.surfaceAreaSqFt = sqft;
|
||||
}
|
||||
|
||||
wz.data.quantity = parseInt(document.getElementById('wz_quantity')?.value) || 1;
|
||||
wz.data.quantity = parseFloat(document.getElementById('wz_quantity')?.value) || 1;
|
||||
wz.data.estimatedMinutes = parseInt(document.getElementById('wz_estimatedMinutes')?.value) || 30;
|
||||
}
|
||||
|
||||
@@ -2677,7 +2677,7 @@ function collectStep2() {
|
||||
wz.data.manualUnitPrice = price;
|
||||
}
|
||||
|
||||
wz.data.quantity = parseInt(document.getElementById('wz_quantity')?.value) || 1;
|
||||
wz.data.quantity = parseFloat(document.getElementById('wz_quantity')?.value) || 1;
|
||||
wz.data.notes = document.getElementById('wz_notes')?.value?.trim() || null;
|
||||
wz.data.surfaceAreaSqFt = 0;
|
||||
wz.data.estimatedMinutes = 0;
|
||||
@@ -2723,7 +2723,7 @@ function collectStep2() {
|
||||
wz.data.manualUnitPrice = price;
|
||||
}
|
||||
|
||||
wz.data.quantity = parseInt(document.getElementById('wz_quantity')?.value) || 1;
|
||||
wz.data.quantity = parseFloat(document.getElementById('wz_quantity')?.value) || 1;
|
||||
wz.data.notes = document.getElementById('wz_notes')?.value?.trim() || null;
|
||||
wz.data.surfaceAreaSqFt = 0;
|
||||
wz.data.estimatedMinutes = 0;
|
||||
@@ -2750,7 +2750,7 @@ function collectStep2() {
|
||||
if (valid) {
|
||||
const templates = pageMeta.customFormulaTemplates || [];
|
||||
const tmpl = templates.find(t => t.id === templateId);
|
||||
const qty = parseInt(document.getElementById('wz_formula_qty')?.value) || 1;
|
||||
const qty = parseFloat(document.getElementById('wz_formula_qty')?.value) || 1;
|
||||
const descEl = document.getElementById('wz_formula_description');
|
||||
|
||||
wz.data.quantity = qty;
|
||||
@@ -2788,7 +2788,7 @@ function collectStep2() {
|
||||
wz.data.surfaceAreaSqFt = sqft;
|
||||
wz.data.complexity = complexity;
|
||||
wz.data.estimatedMinutes = minutes;
|
||||
wz.data.quantity = parseInt(document.getElementById('ai_quantity')?.value) || 1;
|
||||
wz.data.quantity = parseFloat(document.getElementById('ai_quantity')?.value) || 1;
|
||||
wz.data.aiReferenceDim = document.getElementById('ai_referenceDim')?.value?.trim() || '';
|
||||
wz.data.aiColor = document.getElementById('ai_color')?.value?.trim() || '';
|
||||
wz.data.aiCoatCount = parseInt(document.getElementById('ai_coatCount')?.value) || 1;
|
||||
@@ -2867,7 +2867,7 @@ function collectStep3() {
|
||||
coat.powderToOrder = orderQtyVal ? parseFloat(orderQtyVal) : null;
|
||||
} else {
|
||||
const sqft = parseFloat(wz.data.surfaceAreaSqFt) || 0;
|
||||
const qty = parseInt(wz.data.quantity) || 1;
|
||||
const qty = parseFloat(wz.data.quantity) || 1;
|
||||
if (sqft > 0 && coat.coverageSqFtPerLb > 0) {
|
||||
const eff = (coat.transferEfficiency || 65) / 100;
|
||||
coat.powderToOrder = (sqft * qty) / (coat.coverageSqFtPerLb * eff);
|
||||
|
||||
Reference in New Issue
Block a user