diff --git a/spoolman/database/spool.py b/spoolman/database/spool.py index 9805498..89adf61 100644 --- a/spoolman/database/spool.py +++ b/spoolman/database/spool.py @@ -376,12 +376,12 @@ async def measure(db: AsyncSession, spool_id: int, weight: float) -> models.Spoo initial_gross_weight = initial_weight + spool_weight - # Calculate the current gross weight (initial_weight - used_weight) - current_use = initial_gross_weight - spool_info[1] + # if the measurement is greater than the initial weight, set the initial weight to the measurement + if weight > initial_gross_weight: + return await reset_initial_weight(db, spool_id, weight - spool_weight) - # if the measurement is greater than the initial weight, raise an error - if weight > current_use: - raise SpoolMeasureError("Measured weight cannot increase.") + # Calculate the current net weight + current_use = initial_gross_weight - spool_info[1] # Calculate the weight used since last measure weight_to_use = current_use - weight @@ -424,3 +424,14 @@ async def spool_changed(spool: models.Spool, typ: EventType) -> None: payload=Spool.from_db(spool), ), ) + + +async def reset_initial_weight(db: AsyncSession, spool_id: int, weight: float) -> models.Spool: + """Reset inital weight to new weight and used_weight to 0.""" + spool = await get_by_id(db, spool_id) + + spool.initial_weight = weight + spool.used_weight = 0 + await db.commit() + await spool_changed(spool, EventType.UPDATED) + return spool diff --git a/tests_integration/tests/spool/test_measure.py b/tests_integration/tests/spool/test_measure.py index 2d1c2c8..567729d 100644 --- a/tests_integration/tests/spool/test_measure.py +++ b/tests_integration/tests/spool/test_measure.py @@ -57,7 +57,7 @@ def test_measure_spool(random_filament: dict[str, Any], measurement: float): @pytest.mark.parametrize("measurement", [1500]) # 1500 is more than the initial weight -def test_measure_spool_invalid(random_filament: dict[str, Any], measurement: float): +def test_measure_spool_higher_initial(random_filament: dict[str, Any], measurement: float): """Test using a spool in the database.""" # Setup random_filament["weight"] @@ -83,13 +83,27 @@ def test_measure_spool_invalid(random_filament: dict[str, Any], measurement: flo }, ) # Update is invalid if the weight is more than the initial weight - assert result.status_code == 400 + result.raise_for_status() + # Verify + spool = result.json() + # remaining_weight should be clamped so it's never negative, + # but used_weight should not be clamped to the net weight + expected_use = 0 + expected_initial_weight = measurement - spool_weight + expected_remaining = max(measurement - spool_weight, 0) + + assert spool["used_weight"] == pytest.approx(expected_use) + assert spool["remaining_weight"] == pytest.approx(expected_remaining) + assert spool["initial_weight"] == pytest.approx(expected_initial_weight) # Clean up httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status() -@pytest.mark.parametrize("measurements", [[1244, 1233, 1200], [1000, 900, 800], [1000, 1000, 1000]]) +@pytest.mark.parametrize( + "measurements", + [[1244, 1233, 1200], [1000, 900, 800], [1000, 1000, 1000], [1000, 900, 800, 815]], +) def test_measure_spool_sequence(random_filament: dict[str, Any], measurements: list[float]): """Test using a spool in the database.""" # Setup