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>
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
"""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,
|
|
}
|