Add cost/time estimate card to job detail page
app/estimation.py: - 20% infill → material volume → weight (density per material) - print time at 20 g/h (conservative FDM average) - filament cost at FILAMENT_PRICE_PER_KG EUR/kg (env, default 15) - +20% misprint buffer, +30% gross profit margin - net price (ex. VAT) and gross price (VAT_RATE %, env, default 19) Card shows three columns: Material & Time / Production cost / Suggested price. Only rendered when STL volume is available. Assumptions shown in card header. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
55
app/estimation.py
Normal file
55
app/estimation.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Job cost and time estimation from STL geometry."""
|
||||
import os
|
||||
|
||||
# g/cm³ per material — used to convert volume → weight
|
||||
_DENSITY: dict[str, float] = {
|
||||
"PLA": 1.24,
|
||||
"PETG": 1.27,
|
||||
"ABS": 1.04,
|
||||
"ASA": 1.07,
|
||||
"TPU": 1.20,
|
||||
"Nylon": 1.14,
|
||||
"PC": 1.20,
|
||||
}
|
||||
_DEFAULT_DENSITY = 1.24
|
||||
|
||||
# Conservative average FDM print speed for weight-based time estimate
|
||||
_PRINT_SPEED_G_PER_HOUR = 20.0
|
||||
|
||||
|
||||
def estimate(volume_ccm: float, material: str | None) -> dict:
|
||||
"""
|
||||
Returns a cost/time estimate dict for one job.
|
||||
|
||||
Assumptions:
|
||||
- 20 % infill → material used = volume * 0.20
|
||||
- filament density from _DENSITY (default 1.24 g/cm³)
|
||||
- print speed: 20 g/h (conservative FDM average)
|
||||
- filament cost: FILAMENT_PRICE_PER_KG EUR / kg (env, default 15)
|
||||
- misprint buffer: +20 %
|
||||
- gross profit margin: +30 %
|
||||
- VAT: VAT_RATE % (env, default 19)
|
||||
"""
|
||||
vat_rate = float(os.environ.get("VAT_RATE", 19))
|
||||
price_per_kg = float(os.environ.get("FILAMENT_PRICE_PER_KG", 15))
|
||||
density = _DENSITY.get(material or "", _DEFAULT_DENSITY)
|
||||
|
||||
material_ccm = volume_ccm * 0.20
|
||||
weight_g = material_ccm * density
|
||||
print_minutes = round((weight_g / _PRINT_SPEED_G_PER_HOUR) * 60)
|
||||
|
||||
filament_cost = weight_g / 1000 * price_per_kg
|
||||
after_misprint = filament_cost * 1.20
|
||||
net_price = after_misprint * 1.30
|
||||
gross_price = net_price * (1 + vat_rate / 100)
|
||||
|
||||
return {
|
||||
"material_ccm": round(material_ccm, 2),
|
||||
"weight_g": round(weight_g, 1),
|
||||
"print_minutes": print_minutes,
|
||||
"filament_cost": round(filament_cost, 2),
|
||||
"net_price": round(net_price, 2),
|
||||
"gross_price": round(gross_price, 2),
|
||||
"vat_rate": vat_rate,
|
||||
"price_per_kg": price_per_kg,
|
||||
}
|
||||
Reference in New Issue
Block a user