pricing.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. from typing import List
  2. import db
  3. import config
  4. def calculate_estimated_price(material_id: int, file_sizes: List[int], file_quantities: List[int] = None, return_details=False) -> float:
  5. """
  6. Internal logic to estimate price per file based on file size (proxy for volume)
  7. and print time (proxy for machine wear/energy).
  8. """
  9. material = db.execute_query("""
  10. SELECT m.price_per_cm3,
  11. COALESCE(NULLIF(m.price_per_hour, 0), s.price_per_hour, %s) as price_per_hour,
  12. m.speed_coeff
  13. FROM materials m
  14. LEFT JOIN services s ON m.service_id = s.id
  15. WHERE m.id = %s
  16. """, (config.DEFAULT_PRINTER_HOUR_PRICE, material_id))
  17. if not material:
  18. return (0.0, []) if return_details else 0.0
  19. price_per_cm3 = float(material[0]['price_per_cm3'])
  20. price_per_hour = float(material[0]['price_per_hour'])
  21. speed_coeff = float(material[0]['speed_coeff'] or 1.0)
  22. if file_quantities is None or len(file_quantities) != len(file_sizes):
  23. file_quantities = [1] * len(file_sizes)
  24. # Volume discount: 5% for each next item, max 20% total
  25. total_qty = sum(file_quantities)
  26. discount_multiplier = 1.0
  27. discount_percent = 0.0
  28. if total_qty > 1:
  29. discount_percent = min((total_qty - 1) * 0.05, 0.20)
  30. discount_multiplier = 1.0 - discount_percent
  31. estimated_total = 0.0
  32. file_costs = []
  33. base_fee = 0.0 # No setup fee
  34. for size, qty in zip(file_sizes, file_quantities):
  35. total_size_mb = size / (1024 * 1024)
  36. # Empirical conversion: ~8cm3 per 1MB of STL (binary)
  37. estimated_volume_cm3 = total_size_mb * 8.0
  38. # Estimate printing time (same logic as in slicer_utils.py: volume_mm3 / 10.0)
  39. # Apply speed_coeff to adjust time based on material difficulty
  40. estimated_hours = ((estimated_volume_cm3 * 100.0) / 3600.0) * speed_coeff
  41. material_cost = estimated_volume_cm3 * price_per_cm3
  42. operation_cost = estimated_hours * price_per_hour
  43. # Apply volume discount to unit price
  44. file_cost = round((base_fee + material_cost + operation_cost) * discount_multiplier, 2)
  45. file_costs.append(file_cost)
  46. estimated_total += file_cost * qty
  47. metadata = {
  48. "price_per_cm3": price_per_cm3,
  49. "price_per_hour": price_per_hour,
  50. "speed_coeff": speed_coeff,
  51. "base_fee": base_fee,
  52. "discount_percent": round(discount_percent * 100, 0),
  53. "total_qty": total_qty
  54. }
  55. if return_details:
  56. return round(estimated_total, 2), file_costs, metadata
  57. return round(estimated_total, 2)