Use NCR business number in URLs (/ncrs/NCR-2026-0021)

Detail routes, queue navigation, and notification email links now use the
business identifier instead of the database id — friendlier for end users
quoting NCR numbers. The API resolves both forms (case-insensitive number,
or legacy numeric id) so existing bookmarks and email links keep working.
Adds regression tests incl. a guard that /ncrs/export.csv isn't shadowed
by the path parameter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
ang3l12
2026-07-28 11:15:16 -06:00
parent 12383b2225
commit 8d48f774bb
7 changed files with 102 additions and 44 deletions

View File

@@ -0,0 +1,44 @@
"""NCR lookup by business identifier (URL paths) with legacy-id fallback."""
from .util import create_ncr, do_initial_disposition, hdr
async def test_lookup_by_business_number(client, team):
ncr = await create_ncr(client, team)
number = ncr["ncr_number"]
r = await client.get(f"/api/ncrs/{number}", headers=hdr(team["requester"]))
assert r.status_code == 200
assert r.json()["id"] == ncr["id"]
# case-insensitive
r = await client.get(f"/api/ncrs/{number.lower()}", headers=hdr(team["requester"]))
assert r.status_code == 200
async def test_stage_actions_work_by_business_number(client, team):
ncr = await create_ncr(client, team)
r = await do_initial_disposition(client, team, ncr["ncr_number"])
assert r.status_code == 200, r.text
assert r.json()["ncr"]["stage"] == "operations"
async def test_legacy_numeric_id_still_resolves(client, team):
"""Old email links used /ncrs/<database id>; they must keep working."""
ncr = await create_ncr(client, team)
r = await client.get(f"/api/ncrs/{ncr['id']}", headers=hdr(team["requester"]))
assert r.status_code == 200
assert r.json()["ncr_number"] == ncr["ncr_number"]
async def test_unknown_refs_are_404(client, team):
for ref in ("NCR-1999-9999", "999999", "not-a-number-at-all"):
r = await client.get(f"/api/ncrs/{ref}", headers=hdr(team["requester"]))
assert r.status_code == 404, ref
async def test_csv_export_route_not_shadowed(client, team):
"""/ncrs/export.csv must match the literal route, not the {ncr_ref} param."""
await create_ncr(client, team)
r = await client.get("/api/ncrs/export.csv?queue=all", headers=hdr(team["requester"]))
assert r.status_code == 200
assert r.headers["content-type"].startswith("text/csv")