Skip to content

feat(spp_drims): Incident Management review — states, closed-incident limits, dashboard and warehouses - #416

Open
emjay0921 wants to merge 14 commits into
19.0from
feat/1100-drims-incident-management
Open

feat(spp_drims): Incident Management review — states, closed-incident limits, dashboard and warehouses#416
emjay0921 wants to merge 14 commits into
19.0from
feat/1100-drims-incident-management

Conversation

@emjay0921

Copy link
Copy Markdown
Contributor

Why is this change needed?

OP#1100 (DRIMS - Full review - Incident Management) and all of its children have passed QA — this raises the PR for that work, per the flow of opening PRs once QA signs off.

Ticket Status
OP#1094 Invalidate stock KPI cache when warehouses change Closed
OP#1123 Dashboard KPI boxes navigate unexpectedly Test pass
OP#1157 Enable "Alert" state for incidents Test pass
OP#1158 Limit possible actions on incidents in state "Closed" Test pass
OP#1159 Hide "Impact" tab on Incidents Test pass
OP#1160 Changes to Incident Dashboard view Test pass
OP#1164 Add warehouses to an incident Test pass

What is in here

  • Incident lifecycle (OP#1157) — an incident is now entered as a Draft and classified from there, with Flag As Alert and Set Active offered side by side. The lifecycle is Draft → Alert or Active → Recovery → Closed, and Alert stays reachable later. Draft was added to the list's default filter, or a newly recorded incident would have disappeared from the list it was created in.
  • Closed incidents are inert (OP#1158) — submitting, approving and allocating requests, accepting donations, deploying personnel and editing incident fields are all refused once an incident is closed, and the Hazard Category no longer links out.
  • Incident warehouses (OP#1164) — warehouses and incidents are linked bidirectionally, and the donation and request pickers filter to the incident's warehouses.
  • Dashboard (OP#1160, OP#1123, OP#1094) — Units/Products counts incident stock net of allocations and Distributed is net of returns; clicking a KPI box no longer navigates away, only the incident name opens the form; and the stock-value KPI refreshes when a warehouse's incidents change.
  • Impact tab hidden (OP#1159) pending OP#1155.

Unit tests executed by the author

On the merged branch, across the base module and everything downstream of it:

spp_hazard             0 failed, 0 error(s) of  71 tests
spp_hazard_programs    0 failed, 0 error(s) of  24 tests
spp_drims              0 failed, 0 error(s) of 284 tests
spp_drims_sl           0 failed, 0 error(s) of   3 tests
spp_drims_sl_demo      0 failed, 0 error(s) of   8 tests

./spp lint --all-files clean.

How to test manually

  1. Create an incident — it saves as Draft and offers exactly Flag As Alert and Set Active. Confirm it still appears in the incident list.
  2. Classify it either way, then walk Active → Recovery → Closed.
  3. On a closed incident: its fields are read-only, Hazard Category is plain text rather than a link, and a request or donation against it is refused.
  4. Link a warehouse to an incident and confirm the donation and request pickers narrow to it.
  5. On the dashboard, click a KPI box — it must not navigate; only the incident name opens the form.

Related links

https://openspp.openproject.com/work_packages/1100

Reviewer notes

OP#1157 changed requirement twice, which is why its history on this branch is three commits. Round 1 exposed the existing Alert state via a button; round 2 made Alert the entry state; round 3 replaced that with a new Draft state, because QA wanted the person recording an incident to say what it is rather than have Alert assumed. The final shape is round 3.

Two decisions were made where the ticket was silent, both confirmed by QA on the ticket: a draft cannot be closed — a mistaken one is deleted — and a draft does not count as a live incident anywhere (not "ongoing", not marking registrants affected, and not offered where only Active incidents are, such as low-stock alerting and the request-from-template picker). It starts counting once classified.

spp_hazard is a base module with dependants, so the runs above cover both modules that inherit the incident form, not just the module under change.

The branch was brought up to date by merging 19.0, not rebasing, since it was already published.

emjay0921 added 14 commits July 24, 2026 12:13
…of allocations) and Distributed net of returns (#1160)
QA round 1 on OP#1157 returned three findings and a question.

Flag As Alert was inserted before the statusbar, which rendered it last.
It is now anchored on the first header button so the order reads Flag As
Alert, Start Recovery, Close Incident — the order the workflow runs in.
Anchored by button name rather than position, so a reordering of the base
view fails loudly at upgrade instead of silently drifting back.

New incidents landed straight in Active, skipping the triage step the
Alert state exists for. The status default becomes "alert", making the
lifecycle Alert -> Active -> Recovery -> Closed. Changed on spp_hazard,
where the state machine lives, so every consumer behaves the same rather
than the same model behaving differently depending on which modules are
installed.

Close Incident was already correct in effect — with four states,
"not closed" and "alert, active or recovery" are the same set — but it is
now stated positively so it stays right if a state is ever added.

QA also asked when Recovery can be set: only from Active, since Start
Recovery is hidden otherwise. With Alert as the entry state a new incident
is confirmed Active before Recovery is offered. A test pins that so the
answer does not quietly change.

Four spp_hazard tests asserted the old default; they now confirm Active
explicitly rather than assuming it.

Not changed, and flagged for QA instead: DRIMS low-stock alerting and the
request-from-template picker both filter on status = "active", so an
incident sitting in Alert reaches neither until it is confirmed. Whether an
alert-state incident should drive stock alerting is a product decision.

Verified across every spp_hazard dependent — spp_hazard, spp_drims,
spp_hazard_programs, spp_api_v2_gis, spp_gis_indicators, spp_drims_sl_demo
— and by hand on a fresh database.

OP#1157
Closing an incident left Hazard Category clickable, so a closed record
still offered a way through to the category form. Making the field
readonly does not cover this — a readonly many2one still renders as an
internal link — and no_open cannot be made conditional, because options is
parsed as a static dict and cannot reference status.

Declare the field twice instead, with mutually exclusive invisible: an open
incident keeps its link, a closed one is inert text. The same pattern is
already used across the codebase wherever a field has to change shape with
state.

Asserted on the arch rather than through behaviour, since whether a
many2one is clickable is decided in the client, not the ORM.
…ent-management

# Conflicts:
#	spp_drims/models/request.py
#	spp_drims/views/request_views.xml
OP#1079 made the request line's quantity_allocated a stored compute over
per-warehouse allocation rows, so the helper's direct write no longer
registered and the Units KPI counted stock that had in fact been allocated.
Round 2 made Alert the entry state. QA has since changed the requirement: an
incident should be entered as a draft, and the person recording it says what
it is — Flag As Alert for something being watched, Set Active for a response
already under way. Neither is assumed on their behalf.

Adds a draft state at the head of the selection and makes it the default.
Set Active is now offered from Draft as well, so a response already under way
does not have to be flagged as an alert first. Start Recovery and Close
Incident stay hidden there, which is what leaves a draft showing exactly the
two buttons asked for.

The list's default filter needed Draft adding too. It pre-selects Alert,
Active and Recovery, so with Draft as the entry state a newly created
incident would have disappeared from the list it was created in and read as
having failed to save. A test asserts both the filter and its default,
because nothing at the model level would notice.

A draft is deliberately not a live incident: it is excluded from is_ongoing,
from the affected-registrant check, and from the Active-only consumers. It
starts counting once classified. A draft also cannot be closed — a mistaken
one is deleted rather than closed.

Six tests asserting the round-2 lifecycle are rewritten, not dropped.
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.00990% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 72.85%. Comparing base (0820667) to head (1d7db31).

Files with missing lines Patch % Lines
spp_drims/models/hazard_incident.py 98.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             19.0     #416      +/-   ##
==========================================
+ Coverage   72.24%   72.85%   +0.60%     
==========================================
  Files         419      464      +45     
  Lines       29813    31568    +1755     
==========================================
+ Hits        21539    22998    +1459     
- Misses       8274     8570     +296     
Flag Coverage Δ
spp_api_v2_change_request 66.53% <ø> (ø)
spp_api_v2_cycles 71.03% <ø> (ø)
spp_api_v2_entitlements 70.23% <ø> (ø)
spp_api_v2_gis 71.57% <ø> (ø)
spp_api_v2_programs 92.22% <ø> (ø)
spp_api_v2_simulation 71.19% <ø> (?)
spp_base_common 91.07% <ø> (ø)
spp_case_entitlements 100.00% <ø> (?)
spp_case_programs 100.00% <ø> (?)
spp_change_request_v2 77.83% <ø> (ø)
spp_cr_type_assign_program 92.07% <ø> (ø)
spp_dci_compliance 93.01% <ø> (?)
spp_drims 83.39% <99.00%> (+1.15%) ⬆️
spp_hazard 100.00% <ø> (?)
spp_programs 65.27% <ø> (ø)
spp_registry 87.22% <ø> (+0.07%) ⬆️
spp_security 69.56% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
spp_drims/models/donation.py 97.05% <100.00%> (+0.14%) ⬆️
spp_drims/models/personnel.py 98.41% <100.00%> (+0.16%) ⬆️
spp_drims/models/request.py 93.46% <100.00%> (+0.26%) ⬆️
spp_drims/models/res_config_settings.py 63.79% <100.00%> (+2.68%) ⬆️
spp_drims/models/returns.py 93.06% <ø> (ø)
spp_drims/models/stock_warehouse.py 77.94% <100.00%> (+7.35%) ⬆️
spp_hazard/models/hazard_incident.py 100.00% <ø> (ø)
spp_drims/models/hazard_incident.py 75.59% <98.00%> (+10.31%) ⬆️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@emjay0921
emjay0921 marked this pull request as ready for review August 14, 2026 03:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant