| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- """An archive's cost is the cost of one print of it.
- Completion stores the first run's cost on the archive and every run's own cost
- on its Print History entry (#1378). "Recalculate costs" and "Rescan" used to
- sum the spool usage of every run, so an archive printed three times was priced
- three times over; editing its grams repriced nothing.
- """
- import pytest
- from httpx import AsyncClient
- from sqlalchemy import select
- from backend.app.models.print_log import PrintLogEntry
- from backend.app.models.spool_usage_history import SpoolUsageHistory
- async def _archive(archive_factory, printer_factory, db_session, *, grams, cost=None, with_run=True):
- printer = await printer_factory()
- archive = await archive_factory(
- printer.id,
- print_name="Bracket",
- status="completed",
- cost=cost,
- filament_used_grams=grams,
- filament_type="PLA",
- with_run=with_run,
- )
- return archive.id
- async def _usage(db_session, archive_id, *rows):
- for grams, cost in rows:
- db_session.add(SpoolUsageHistory(archive_id=archive_id, weight_used=grams, cost=cost, print_name="Bracket"))
- await db_session.commit()
- async def _cost(async_client, archive_id):
- response = await async_client.get(f"/api/v1/archives/{archive_id}")
- assert response.status_code == 200
- return response.json()["cost"]
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_recalculate_prices_one_print_of_an_archive_printed_twice(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=100.0)
- await _usage(db_session, archive_id, (100.0, 3.0), (100.0, 3.0))
- assert (await async_client.post("/api/v1/archives/recalculate-costs")).status_code == 200
- assert await _cost(async_client, archive_id) == 3.0
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_recalculate_still_prices_untracked_grams_at_the_default(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- """One run, half the grams on an inventory spool (#1344): 50 g at the
- spool's 2.00 plus 50 g at the 25/kg default."""
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=100.0)
- await _usage(db_session, archive_id, (50.0, 2.0))
- assert (await async_client.post("/api/v1/archives/recalculate-costs")).status_code == 200
- assert await _cost(async_client, archive_id) == 3.25
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_editing_grams_prices_the_archive_and_its_run(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- """A print archived without its 3MF has neither grams nor cost (#1820)."""
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=None)
- response = await async_client.patch(f"/api/v1/archives/{archive_id}", json={"filament_used_grams": 120})
- assert response.status_code == 200
- assert response.json()["cost"] == 3.0
- run = await db_session.scalar(select(PrintLogEntry).where(PrintLogEntry.archive_id == archive_id))
- await db_session.refresh(run)
- assert (run.filament_used_grams, run.cost) == (120, 3.0)
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_a_cost_given_with_the_grams_is_kept(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=100.0, cost=2.5)
- response = await async_client.patch(
- f"/api/v1/archives/{archive_id}", json={"filament_used_grams": 200, "cost": 9.99}
- )
- assert response.json()["cost"] == 9.99
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_a_run_that_measured_its_own_grams_keeps_its_cost(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=100.0, cost=2.5)
- run = await db_session.scalar(select(PrintLogEntry).where(PrintLogEntry.archive_id == archive_id))
- run.filament_used_grams, run.cost = 37.0, 1.11
- await db_session.commit()
- response = await async_client.patch(f"/api/v1/archives/{archive_id}", json={"filament_used_grams": 200})
- assert response.json()["cost"] == 5.0
- await db_session.refresh(run)
- assert (run.filament_used_grams, run.cost) == (37.0, 1.11)
- async def _runs(db_session, archive_id, *grams):
- for g in grams:
- db_session.add(PrintLogEntry(archive_id=archive_id, status="completed", filament_used_grams=g))
- await db_session.commit()
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_recalculate_keeps_the_untracked_share_of_every_run(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- """Printed three times, half of each 100 g run on a 60/kg spool: one print
- is 50 g at 0.06 plus 50 g at the 25/kg default, as completion priced it."""
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=100.0)
- await _runs(db_session, archive_id, 100.0, 100.0)
- await _usage(db_session, archive_id, (50.0, 3.0), (50.0, 3.0), (50.0, 3.0))
- assert (await async_client.post("/api/v1/archives/recalculate-costs")).status_code == 200
- assert await _cost(async_client, archive_id) == 4.25
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_recalculate_prices_unpriced_usage_at_the_default(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- """A usage row recorded without a price is not free filament."""
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=100.0)
- await _usage(db_session, archive_id, (50.0, 2.0), (50.0, None))
- assert (await async_client.post("/api/v1/archives/recalculate-costs")).status_code == 200
- assert await _cost(async_client, archive_id) == 3.25
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_recalculate_without_grams_prices_an_average_run(
- async_client: AsyncClient, archive_factory, printer_factory, db_session
- ):
- """Archived without its 3MF, so no grams: the spool usage of its two runs
- still prices one of them."""
- archive_id = await _archive(archive_factory, printer_factory, db_session, grams=None)
- await _runs(db_session, archive_id, None)
- await _usage(db_session, archive_id, (40.0, 2.0), (40.0, 2.0))
- assert (await async_client.post("/api/v1/archives/recalculate-costs")).status_code == 200
- assert await _cost(async_client, archive_id) == 2.0
|