from typing import List import db import config def calculate_estimated_price(material_id: int, file_sizes: List[int], file_quantities: List[int] = None, return_details=False) -> float: """ Internal logic to estimate price per file based on file size (proxy for volume) and print time (proxy for machine wear/energy). """ material = db.execute_query(""" SELECT m.price_per_cm3, COALESCE(NULLIF(m.price_per_hour, 0), s.price_per_hour, %s) as price_per_hour, m.speed_coeff FROM materials m LEFT JOIN services s ON m.service_id = s.id WHERE m.id = %s """, (config.DEFAULT_PRINTER_HOUR_PRICE, material_id)) if not material: return (0.0, []) if return_details else 0.0 price_per_cm3 = float(material[0]['price_per_cm3']) price_per_hour = float(material[0]['price_per_hour']) speed_coeff = float(material[0]['speed_coeff'] or 1.0) if file_quantities is None or len(file_quantities) != len(file_sizes): file_quantities = [1] * len(file_sizes) # Volume discount: 5% for each next item, max 20% total total_qty = sum(file_quantities) discount_multiplier = 1.0 discount_percent = 0.0 if total_qty > 1: discount_percent = min((total_qty - 1) * 0.05, 0.20) discount_multiplier = 1.0 - discount_percent estimated_total = 0.0 file_costs = [] base_fee = 5.0 # Minimum setup fee per file for size, qty in zip(file_sizes, file_quantities): total_size_mb = size / (1024 * 1024) # Empirical conversion: ~8cm3 per 1MB of STL (binary) estimated_volume_cm3 = total_size_mb * 8.0 # Estimate printing time (same logic as in slicer_utils.py: volume_mm3 / 10.0) # Apply speed_coeff to adjust time based on material difficulty estimated_hours = ((estimated_volume_cm3 * 100.0) / 3600.0) * speed_coeff material_cost = estimated_volume_cm3 * price_per_cm3 operation_cost = estimated_hours * price_per_hour # Apply volume discount to unit price file_cost = round((base_fee + material_cost + operation_cost) * discount_multiplier, 2) file_costs.append(file_cost) estimated_total += file_cost * qty metadata = { "price_per_cm3": price_per_cm3, "price_per_hour": price_per_hour, "speed_coeff": speed_coeff, "base_fee": base_fee, "discount_percent": round(discount_percent * 100, 0), "total_qty": total_qty } if return_details: return round(estimated_total, 2), file_costs, metadata return round(estimated_total, 2)