test_slot_materials_cost.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. """The print dialog's estimate prices each slot at the rate its print is charged.
  2. The dialog priced slots from the built-in assignment table in both inventory
  3. modes. In Spoolman mode that table holds nothing, or rows from before the
  4. switch, so the estimate used the default rate or a spool the printer is not
  5. drawing on, while the print was charged the Spoolman spool's price. The
  6. mode-aware slot payload now carries each slot's rate.
  7. """
  8. from unittest.mock import AsyncMock, patch
  9. import pytest
  10. from backend.app.models.settings import Settings
  11. from backend.app.models.spool import Spool
  12. from backend.app.models.spool_assignment import SpoolAssignment
  13. from backend.app.models.spoolman_slot_assignment import SpoolmanSlotAssignment
  14. from backend.app.services.filament_deficit import build_slot_materials
  15. from backend.tests.unit.services import test_filament_deficit as _deficit_tests
  16. pytestmark = pytest.mark.asyncio
  17. async def _slots(db_session, printer_id: int, client=None):
  18. patches = _deficit_tests.TestFilamentDeficitBackupAware._patch_status(
  19. printer_id=printer_id, backup_on=False, model="X1C"
  20. )
  21. for p in patches:
  22. p.start()
  23. try:
  24. with patch("backend.app.services.spoolman.get_spoolman_client", AsyncMock(return_value=client)):
  25. return {s.global_tray_id: s for s in await build_slot_materials(db_session, printer_id)}
  26. finally:
  27. for p in patches:
  28. p.stop()
  29. async def test_spoolman_slots_carry_the_charged_rate(db_session, printer_factory):
  30. printer = await printer_factory(model="X1C")
  31. db_session.add(Settings(key="spoolman_enabled", value="true"))
  32. for tray_id in range(3):
  33. db_session.add(
  34. SpoolmanSlotAssignment(printer_id=printer.id, ams_id=0, tray_id=tray_id, spoolman_spool_id=10 + tray_id)
  35. )
  36. await db_session.commit()
  37. spools = {
  38. # The spool's own price, over its own net weight.
  39. 10: {"id": 10, "remaining_weight": 200.0, "price": 10.0, "initial_weight": 250.0, "filament": {"id": 1}},
  40. # No spool price: the filament's, over the filament's weight.
  41. 11: {"id": 11, "remaining_weight": 900.0, "filament": {"id": 2, "price": 30.0, "weight": 1000.0}},
  42. # Unpriced: no rate, so the dialog uses the default as the charge does.
  43. 12: {"id": 12, "remaining_weight": 500.0, "filament": {"id": 3}},
  44. }
  45. client = AsyncMock()
  46. client.get_spool = AsyncMock(side_effect=lambda sid: spools[sid])
  47. slots = await _slots(db_session, printer.id, client)
  48. assert slots[0].cost_per_kg == pytest.approx(40.0)
  49. assert slots[1].cost_per_kg == pytest.approx(30.0)
  50. assert slots[2].cost_per_kg is None
  51. assert slots[0].to_dict()["cost_per_kg"] == pytest.approx(40.0)
  52. async def test_built_in_slots_carry_the_spool_s_rate(db_session, printer_factory):
  53. printer = await printer_factory(model="X1C")
  54. priced = Spool(material="PLA", label_weight=1000, weight_used=0.0, cost_per_kg=22.5)
  55. unpriced = Spool(material="PLA", label_weight=1000, weight_used=0.0)
  56. db_session.add_all([priced, unpriced])
  57. await db_session.commit()
  58. for tray_id, spool in enumerate((priced, unpriced)):
  59. db_session.add(SpoolAssignment(spool_id=spool.id, printer_id=printer.id, ams_id=0, tray_id=tray_id))
  60. await db_session.commit()
  61. slots = await _slots(db_session, printer.id)
  62. assert slots[0].cost_per_kg == 22.5
  63. assert slots[1].cost_per_kg is None