From 30a13644cef111024f3035616a1c35fb2a2a0309 Mon Sep 17 00:00:00 2001
From: Ian Roddis <31021769+iroddis@users.noreply.github.com>
Date: Fri, 31 Jul 2026 09:02:24 -0300
Subject: [PATCH] Adding fit note at manual fit creation
---
app/templates/admin/_augmented_part_fits.html | 3 +
app/web/admin.py | 4 +
tests/test_augmented_part_detail.py | 76 ++++++++++++++++++-
3 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/app/templates/admin/_augmented_part_fits.html b/app/templates/admin/_augmented_part_fits.html
index c5c870a..5c20fbd 100644
--- a/app/templates/admin/_augmented_part_fits.html
+++ b/app/templates/admin/_augmented_part_fits.html
@@ -52,6 +52,9 @@
+
{% endif %}
diff --git a/app/web/admin.py b/app/web/admin.py
index a5daca5..0785630 100644
--- a/app/web/admin.py
+++ b/app/web/admin.py
@@ -2271,6 +2271,7 @@ async def create_augmented_part_fit(
other_augmented_part_id: str = Form(""),
other_attachment_point_id: str = Form(""),
label: FitLabel = Form(FitLabel.EXACT),
+ note: str = Form(""),
db: AsyncSession = Depends(get_db),
actor: User = Depends(web_require("fits:write")),
):
@@ -2335,6 +2336,9 @@ async def create_augmented_part_fit(
"Fit", fit.id, f"attachment points {ap_a.id}↔{ap_b.id} ({label.value})"
),
)
+ if note.strip():
+ await fit_note_crud.create(db, fit=fit, author=actor, body=note.strip())
+ await db.refresh(fit, attribute_names=["notes"])
ctx = await _augmented_part_fits_ctx(
db, augmented_part_id, can_write=_can_write_fits(actor), error=error
)
diff --git a/tests/test_augmented_part_detail.py b/tests/test_augmented_part_detail.py
index f958711..c4c227e 100644
--- a/tests/test_augmented_part_detail.py
+++ b/tests/test_augmented_part_detail.py
@@ -4,7 +4,7 @@ from app.crud import role as role_crud
from app.models.attachment_point import AttachmentPoint
from app.models.attachment_point_name import AttachmentPointName
from app.models.augmented_part import AugmentedPart
-from app.models.fit import Fit, FitLabel
+from app.models.fit import Fit, FitLabel, FitNote
from app.models.iso_thread import IsoThread
from app.models.part_type import PartType
from app.models.scope_info import ScopeInfo
@@ -236,6 +236,80 @@ async def test_create_fit_auto_creates_matching_attachment_point(
assert fits[0].label == FitLabel.POSSIBLE
+@pytest.mark.asyncio
+async def test_create_fit_with_note_creates_fit_note(
+ client, seeded, make_user, db_sessionmaker
+):
+ async with db_sessionmaker() as db:
+ apn = AttachmentPointName(name="Objective")
+ scope_t = PartType(name="Scope")
+ cover_t = PartType(name="Flip Cover")
+ db.add_all([apn, scope_t, cover_t])
+ await db.flush()
+
+ scope = AugmentedPart(
+ description="Alpha 3-18x50",
+ sku="ALP-318",
+ colour_id=1,
+ manufacturer_id=1,
+ part_type_id=scope_t.id,
+ )
+ cover = AugmentedPart(
+ description="Flip cover 50mm",
+ colour_id=1,
+ manufacturer_id=1,
+ part_type_id=cover_t.id,
+ )
+ db.add_all([scope, cover])
+ await db.flush()
+
+ own_ap = AttachmentPoint(
+ augmented_part_id=scope.id, attachment_point_name_id=apn.id
+ )
+ other_ap = AttachmentPoint(
+ augmented_part_id=cover.id, attachment_point_name_id=apn.id
+ )
+ db.add_all([own_ap, other_ap])
+ await db.commit()
+
+ scope_id, own_ap_id, other_ap_id = scope.id, own_ap.id, other_ap.id
+
+ perms = seeded["perms"]
+ editor = await role_crud.create(
+ db,
+ name="fit-editor3",
+ permission_ids=[
+ perms["augmented_parts:read"].id,
+ perms["fits:read"].id,
+ perms["fits:write"].id,
+ ],
+ )
+ editor_id = editor.id
+ await make_user("editor3@example.com", role_ids=[editor_id])
+ await _web_login(client, "editor3@example.com")
+
+ resp = await client.post(
+ f"/admin/augmented-parts/{scope_id}/fits",
+ data={
+ "own_attachment_point_id": own_ap_id,
+ "other_attachment_point_id": other_ap_id,
+ "label": "exact",
+ "note": "Confirmed fit on the bench.",
+ },
+ )
+ assert resp.status_code == 200
+ body = resp.text
+ assert "Confirmed fit on the bench." in body
+
+ async with db_sessionmaker() as db:
+ fits = (await db.execute(Fit.__table__.select())).all()
+ assert len(fits) == 1
+ notes = (await db.execute(FitNote.__table__.select())).all()
+ assert len(notes) == 1
+ assert notes[0].fit_id == fits[0].id
+ assert notes[0].body == "Confirmed fit on the bench."
+
+
@pytest.mark.asyncio
async def test_detail_404_for_missing_part(client, seeded, make_user):
await make_user("reader2@example.com", role_ids=[seeded["roles"]["user"].id])