fix: require activation before sending observation/inquiry to a department
Some checks failed
Build and Push Docker Image / build (push) Failing after 6m52s

An item could be sent to a department while still in its initial (open) state,
bypassing activation. Added a status guard to the 4 send entry points:
- observation_send_to_department / observation_send_to (AJAX)
- inquiry_transfer_to_department / inquiry_send_to (AJAX)
Rejects with "Activate this {observation/inquiry} before sending it to a
department." if status is open. Re-sends after a rejection still work (item
stays in_progress).

Also:
- seed_e2e_dept_response: observation status "new" -> "open" (valid initial;
  "new" isn't a valid ObservationStatus, which is why activate never moved it)
- spec: Flow A/B/C now activate before send
This commit is contained in:
ismail 2026-06-14 21:27:39 +03:00
parent adff7dd8b5
commit 32e2a3f996
4 changed files with 29 additions and 1 deletions

View File

@ -3116,6 +3116,11 @@ def inquiry_transfer_to_department(request, pk):
messages.error(request, _("You don't have permission to transfer inquiries to departments.")) messages.error(request, _("You don't have permission to transfer inquiries to departments."))
return redirect("inquiries:inquiry_detail", pk=pk) return redirect("inquiries:inquiry_detail", pk=pk)
# Must be activated (in_progress) before it can be sent to a department
if inquiry.status == "open":
messages.error(request, _("Activate this inquiry before sending it to a department."))
return redirect("inquiries:inquiry_detail", pk=pk)
department_id = request.POST.get("department_id") department_id = request.POST.get("department_id")
if not department_id: if not department_id:
messages.error(request, _("Please select a department.")) messages.error(request, _("Please select a department."))
@ -3355,6 +3360,13 @@ def inquiry_send_to(request, pk):
"error": str(_("You don't have permission to send this inquiry.")), "error": str(_("You don't have permission to send this inquiry.")),
}, status=403) }, status=403)
# Must be activated (in_progress) before it can be sent/assigned
if inquiry.status == "open":
return JsonResponse({
"success": False,
"error": str(_("Activate this inquiry before sending it to a department.")),
}, status=400)
recipient_type = request.POST.get("recipient_type", "department") recipient_type = request.POST.get("recipient_type", "department")
note = request.POST.get("note", "").strip() note = request.POST.get("note", "").strip()

View File

@ -46,6 +46,6 @@ class Command(BaseCommand):
item = Observation.objects.create( item = Observation.objects.create(
hospital=e2e, hospital=e2e,
description=f"E2E observation dept-response seed #{n}. Automated - please ignore.", description=f"E2E observation dept-response seed #{n}. Automated - please ignore.",
status="new", status="open",
) )
print(f"item_id={item.id} tracking_code={item.tracking_code} department_id={dept.id} champion_staff_id={dept.champion_id}") print(f"item_id={item.id} tracking_code={item.tracking_code} department_id={dept.id} champion_staff_id={dept.champion_id}")

View File

@ -1011,6 +1011,11 @@ def observation_send_to_department(request, pk):
messages.error(request, _("You don't have permission to send observations to departments.")) messages.error(request, _("You don't have permission to send observations to departments."))
return redirect("observations:observation_detail", pk=pk) return redirect("observations:observation_detail", pk=pk)
# Must be activated (in_progress) before it can be sent to a department
if observation.status == ObservationStatus.OPEN:
messages.error(request, _("Activate this observation before sending it to a department."))
return redirect("observations:observation_detail", pk=pk)
department_id = request.POST.get("department_id") department_id = request.POST.get("department_id")
if not department_id: if not department_id:
messages.error(request, _("Please select a department.")) messages.error(request, _("Please select a department."))
@ -1267,6 +1272,13 @@ def observation_send_to(request, pk):
"error": str(_("You don't have permission to send this observation.")), "error": str(_("You don't have permission to send this observation.")),
}, status=403) }, status=403)
# Must be activated (in_progress) before it can be sent/assigned
if observation.status == ObservationStatus.OPEN:
return JsonResponse({
"success": False,
"error": str(_("Activate this observation before sending it to a department.")),
}, status=400)
recipient_type = request.POST.get("recipient_type", "department") recipient_type = request.POST.get("recipient_type", "department")
note = request.POST.get("note", "").strip() note = request.POST.get("note", "").strip()

View File

@ -153,6 +153,8 @@ async function flowA(page: Page, K: KindCfg) {
// 1. PX send - VISIBLE: detail page + Send-to modal // 1. PX send - VISIBLE: detail page + Send-to modal
await login(page, PXT, M); await ensureAuth(page, PXT, M); await login(page, PXT, M); await ensureAuth(page, PXT, M);
// activate first (items can't be sent to a dept until activated)
await postForm(page, `${BASE_URL}${K.activate(itemId)}`, {});
await page.goto(`${BASE_URL}${K.detail(itemId)}`); await page.goto(`${BASE_URL}${K.detail(itemId)}`);
await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('domcontentloaded');
await page.waitForTimeout(700); await page.waitForTimeout(700);
@ -229,6 +231,7 @@ async function flowB(page: Page, K: KindCfg) {
observe(M, 'B-seed', 'INFO', `${K.label} ${itemId}`, { role: CHAMP }); observe(M, 'B-seed', 'INFO', `${K.label} ${itemId}`, { role: CHAMP });
// 1. PX send via token-minting endpoint // 1. PX send via token-minting endpoint
await login(page, PXT, M); await ensureAuth(page, PXT, M); await login(page, PXT, M); await ensureAuth(page, PXT, M);
await postForm(page, `${BASE_URL}${K.activate(itemId)}`, {}); // activate first
await postObs(page, M, `${BASE_URL}${K.sendToken(itemId)}`, { department_id: s.deptId, contact_person_id: s.champStaffId, recipient_type: 'staff', note_en: 'E2E transfer' }, 'B-send-token', PXT); await postObs(page, M, `${BASE_URL}${K.sendToken(itemId)}`, { department_id: s.deptId, contact_person_id: s.champStaffId, recipient_type: 'staff', note_en: 'E2E transfer' }, 'B-send-token', PXT);
const tok = state(K.seedKind, itemId).response_token; const tok = state(K.seedKind, itemId).response_token;
if (!tok || tok === 'NONE') { observe(M, 'B-token', 'FAIL', 'no response_token minted', { role: CHAMP }); return; } if (!tok || tok === 'NONE') { observe(M, 'B-token', 'FAIL', 'no response_token minted', { role: CHAMP }); return; }
@ -267,6 +270,7 @@ async function flowC(page: Page, K: KindCfg) {
const s = seed(K.seedKind); const s = seed(K.seedKind);
itemId = s.itemId; itemId = s.itemId;
await login(page, PXT, M); await ensureAuth(page, PXT, M); await login(page, PXT, M); await ensureAuth(page, PXT, M);
await postForm(page, `${BASE_URL}${K.activate(itemId)}`, {}); // activate first
await postForm(page, `${BASE_URL}${K.sendTo(itemId)}`, { recipient_type: 'department', department_id: s.deptId, contact_person_id: s.champStaffId, note: 'C' }); await postForm(page, `${BASE_URL}${K.sendTo(itemId)}`, { recipient_type: 'department', department_id: s.deptId, contact_person_id: s.champStaffId, note: 'C' });
await login(page, CHAMP, M); await ensureAuth(page, CHAMP, M); await login(page, CHAMP, M); await ensureAuth(page, CHAMP, M);
await postForm(page, `${BASE_URL}${K.deptResponse(itemId)}`, { response_en: 'C first response' }); await postForm(page, `${BASE_URL}${K.deptResponse(itemId)}`, { response_en: 'C first response' });