Skip to content

Over Limit User Visit Alerts#962

Open
zandre-eng wants to merge 11 commits intomainfrom
ze/over-limit-alerts
Open

Over Limit User Visit Alerts#962
zandre-eng wants to merge 11 commits intomainfrom
ze/over-limit-alerts

Conversation

@zandre-eng
Copy link
Copy Markdown
Contributor

@zandre-eng zandre-eng commented Feb 3, 2026

Product Description

If a user visit has ever had an over-limit status then the following message will be shown in the user visit details pane. This message will not be shown if the user visit has either been accepted by the PM or rejected by the NM:

Program Manager:
pm_overlimit_message

Network Manager:
nm_overlimit_message

Users will now correctly see the over-limit flag name and icon for user visits that were marked as over-limit:
pending-pm-over-limit-icons

The over-limit flag will now also be shown with the rest of the flags in the user visit description:
over-limit-flag-desc

It should be noted that the above only applies to new incoming user visits that have an over-limit status. Any pre-existing user visits that have the over-limit status will not receive the flag unless a separate manual migration is done.

Technical Summary

Link to ticket here.

This PR adds a new over_limit flag which gets saved to UserVisit.flag_reason if the incoming user visit is marked as over limit. The purpose of this flag is to be able to correctly show the over limit status of a user visit, even after its status has been changed.

This PR also addresses a pre-existing bug where duplicate flag names were not showing their correct colour. This is because the check for a duplicate flag name had mismatched casing.

Safety Assurance

Safety story

  • Local testing

Automated test coverage

Unit tests exist.

QA Plan

No QA planned.

Labels & Review

  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 3, 2026

Walkthrough

Adds an OVER_LIMIT flag to flags enums, a UserVisit.has_over_limit_flag property, and appends an over_limit validation flag during form processing. Introduces a flag-badges template and updates table rendering to use it, adjusting icon/status logic to include over-limit. Adds an over-limit warning block to the user visit details template. Tests updated to assert the over-limit flag is present on over-limit visits.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • sravfeyn
  • calellowitz
  • pxwxnvermx
  • Charl1996
  • hemant10yadav
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Over Limit User Visit Alerts' directly summarizes the main change: adding user-visible alerts for over-limit visits, which is the primary product feature across all modified files.
Description check ✅ Passed The PR description is directly related to the changeset, providing product-level details (UI messages and flag display), technical rationale (new over_limit flag), safety assurance (local testing and unit tests), and a link to the related ticket.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ze/over-limit-alerts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sravfeyn
Copy link
Copy Markdown
Member

sravfeyn commented Feb 4, 2026

Per the discussion on ticket, I see that we want to display this message when a visit is in 'over-limit' status, but not once it's approved/rejected, right? However this PR seems to display the message even after its approved/rejected?

I am a bit worried about the status being in multiple places on model resulting in further confusion in future. There's currently status, review_status. Some sort of VisitStatusChange might be better long-term. Though perhaps out of scope for this PR

Comment thread commcare_connect/opportunity/models.py Outdated
models.Index(fields=["opportunity", "status"]),
]

def save(self, *args, **kwargs):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify the reasoning behind overriding the save method? As far as I know, only the form-processing code is responsible for marking a visit as “over-limit.” If that’s the case, do we really need to override save? Would it be cleaner to keep this logic in the same place where we mark a visit as over-limit?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning was simply to have a catch-all for setting the flag. If we ever extend the code in the future to set the status as over-limit somewhere else then we don't have to worry about accidentally forgetting to also mark the over-limit flag.

If the above feels overkill and you think we'll only ever mark a visit as "over-limit" in the form processor then I'm happy to remove this save() override.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up changing my approach to use flags, and have decided to remove the save() override altogether (cc6480d).

Copy link
Copy Markdown
Contributor

@hemant10yadav hemant10yadav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for addressing this. I have a small question and one change that needs to be made. I believe we need to update the over-limit condition in render_icons, as well as the flags column logic in the User Visit table.

Comment thread commcare_connect/opportunity/models.py Outdated
status = models.CharField(
max_length=50, choices=VisitValidationStatus.choices, default=VisitValidationStatus.pending
)
is_over_limit = models.BooleanField(default=False)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a new field we can also use the existing flag_reason column and introduce a new over_limit flag. What do you think about this? Are there any possible caveats to this approach?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only caveat I can think of is that it could increase complexity a little, since we will no longer be looking at a boolean field but will now need to parse the flag_reason JSON field. But, I can see the benefit in keeping things more organized.

Let me look into this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a few commits to utilise flags instead of a separate field. Please let me know if there are any concerns with this approach.

Copy link
Copy Markdown
Contributor

@hemant10yadav hemant10yadav Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we currently treat over-limit as a status rather than a flag. If you look at the Deliver tab filters, Over-Limit and Flagged are two distinct filters, and the same separation exists in the User Visit table filters. With this change, those two concepts would effectively converge — is that the intended outcome?

At the same time, we display over-limit as a flag in the visit table, which introduces some inconsistency and potential confusion from both a UX and data-model perspective. I think we should first align on how we want to conceptually represent “over-limit” — whether it should be treated as a status or purely as a flag — before moving forward with the change.

That said, the earlier approach you implemented aligns well with our current setup. However, the final decision should depend on how we want to define and handle the over-limit concept going forward.

{% else %}
<p class="text-sm">
{% blocktranslate %}
This visit has been flagged as over-limit and should not be approved.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we disable the approve button in this case as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. We've added this to the ideas board for further thought, but right now we don't want to block a core workflow.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@commcare_connect/opportunity/tables.py`:
- Around line 950-955: The bug is that code appends
VisitValidationStatus.over_limit.name (a string) to the status list but
get_icons() and status_meta expect enum members as keys; update the branch that
currently appends VisitValidationStatus.over_limit.name to append the enum
member VisitValidationStatus.over_limit instead so the key matches
status_meta/get_icons() (look for the conditional around
record.review_status/record.status/record.has_over_limit_flag and replace the
.name append with the enum member).

In `@commcare_connect/templates/opportunity/partials/user_visit_flag_badges.html`:
- Around line 6-15: The template's comparison flag == "duplicate" is
case-sensitive and won't match values returned by FlagLabels like "Duplicate";
update the conditional in the user_visit_flag_badges.html template to compare in
a case-insensitive way (e.g., use flag|lower == "duplicate") or compare against
the exact "Duplicate" string so the duplicate flag correctly receives the
warning-light badge; adjust the conditional around the span rendering for the
flag variable used in the for-loop (flags, flag).
🧹 Nitpick comments (1)
commcare_connect/form_receiver/processor.py (1)

258-259: Consider using FlagDescription.OVER_LIMIT.value for consistency.

The hardcoded message "User visit exceeds allowed limit." differs slightly from FlagDescription.OVER_LIMIT which is "Visit exceeds allowed limit." While other flags in this file also use hardcoded messages, using the enum value would ensure consistency across the codebase.

That said, the logic correctly appends the over_limit flag when the visit status warrants it.

♻️ Optional: Use enum for consistency
+from commcare_connect.utils.flags import FlagDescription
+
     if user_visit.status == VisitValidationStatus.over_limit:
-        flags.append(["over_limit", "User visit exceeds allowed limit."])
+        flags.append(["over_limit", FlagDescription.OVER_LIMIT.value])

Comment thread commcare_connect/opportunity/tables.py
@zandre-eng
Copy link
Copy Markdown
Contributor Author

@sravfeyn

Per the discussion on ticket, I see that we want to display this message when a visit is in 'over-limit' status, but not once it's approved/rejected, right? However this PR seems to display the message even after its approved/rejected?

I've tweaked the implementation a bit so that when a user visit is approved by PM or rejected by NM then the message will not be shown.

I am a bit worried about the status being in multiple places on model resulting in further confusion in future. There's currently status, review_status. Some sort of VisitStatusChange might be better long-term. Though perhaps out of scope for this PR

I have changed my approach so that we don't use an additional model field anymore, but make use of the existing flags column instead. Let me know if there are any concerns/questions regarding this.

@ajeety4
Copy link
Copy Markdown
Contributor

ajeety4 commented Mar 6, 2026

Hi @zandre-eng ,

I was reading through the ticket and the Slack conversations, and I was wondering whether we can now utilise the status audit history to determine if a visit was over-limit at some stage, given that the status history functionality has now been implemented.

I do like the idea of having this as a flag, though. However, since it is currently used as a status field, it becomes a bit confusing and duplicates it.

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.

6 participants