Skip to content

Conversation

@nandkishorr
Copy link
Contributor

@nandkishorr nandkishorr commented Oct 27, 2025

Merge Checklist

  • Tests added/fixed
  • Update docs in /docs
  • Linting Complete
  • Any other necessary step

Only PR's with test cases included and passing lint and test pipelines will be reviewed

@ohcnetwork/care-backend-maintainers @ohcnetwork/care-backend-admins

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved clarity of error messages for delivery order operations.
    • Updated delivery order access permissions: users now require read access to either the origin or destination facility to view orders.

@nandkishorr nandkishorr requested a review from a team as a code owner October 27, 2025 13:18
@codecov
Copy link

codecov bot commented Oct 27, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.48%. Comparing base (e98e3cd) to head (fa9d840).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3318      +/-   ##
===========================================
+ Coverage    73.19%   73.48%   +0.28%     
===========================================
  Files          435      435              
  Lines        19729    19725       -4     
  Branches      2132     2131       -1     
===========================================
+ Hits         14441    14495      +54     
+ Misses        4849     4790      -59     
- Partials       439      440       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 17, 2025

📝 Walkthrough

Walkthrough

Authorization error messages in the delivery order viewset were updated to reference "delivery orders" instead of "supply requests." The authorize_retrieve logic was revised to require read access to either origin or destination facilities. A comprehensive test suite was added covering creation, update, retrieval, and list operations with various permission scenarios.

Changes

Cohort / File(s) Summary
Authorization and Retrieval Logic
care/emr/api/viewsets/inventory/delivery_order.py
Updated error messages for can_list_facility_supply_delivery and can_write_facility_supply_delivery to reference delivery orders. Revised authorize_retrieve to check read access on either origin or destination facility (using raise_error=False for both checks, then raising if neither grants access). Added docstring documenting the new behavior.
Delivery Order Test Suite
care/emr/tests/test_delivery_order_api.py
New comprehensive Django REST framework test class with setUp infrastructure (users, facilities, organizations, permissions) and helper methods. Covers creation tests (superuser, with/without permission, internal/external contexts), update tests (permission and origin/destination validation), retrieval tests (varying permissions), list tests with multiple filters (origin, destination, status, supplier, include_children, origin_isnull, destination_isnull), filter combinations, edge cases, and error message validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Authorization logic changes: The revisions to authorize_retrieve introduce new conditional logic that warrant careful verification of the raise_error behavior and access control intent.
  • Test comprehensiveness: The large test suite contains many scenarios, though most follow repetitive patterns; however, the edge cases and filter combinations should be traced to ensure they align with intended behavior.
  • Message consistency: Verify the updated error messages propagate correctly and align with other parts of the codebase that may reference delivery order authorization.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete, containing only the merge checklist template items without any 'Proposed Changes' section, issue links, or explanation of what was actually implemented. Add a 'Proposed Changes' section describing the test cases added, include an 'Associated Issue' section with relevant links, and fill out what tests were actually added and fixed.
Title check ❓ Inconclusive The title 'Test cases for delivery order' is vague and overly generic, using non-descriptive terms that don't convey meaningful information about the specific changes. Consider a more specific title that indicates the scope of test coverage, such as 'Add comprehensive test suite for delivery order API' or 'Add delivery order authorization and filtering tests'.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test/delivery_order

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.

Copy link
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: 1

🧹 Nitpick comments (3)
care/emr/api/viewsets/inventory/delivery_order.py (1)

122-137: authorize_retrieve logic matches intent; consider minor readability tweak

The new logic (require read access to origin or destination, using raise_error=False and a single PermissionDenied("Cannot read delivery orders")) matches the docstring and keeps failure messaging consistent. If you ever touch this again, you might consider naming the booleans (origin_allowed, destination_allowed) to avoid the nested parentheses, but as is it’s still quite readable.

care/emr/tests/test_delivery_order_api.py (2)

33-40: FacilityLocationOrganization helper may bind locations to the wrong facility_organization

create_facility_location always uses self.facility_organization, even when creating locations for another facility (e.g., in the mismatched origin/destination test). That can produce FacilityLocationOrganization rows where organization.facility doesn’t match location.facility, which is confusing at best.

It’s a small test‑only thing, but it would be cleaner to either:

  • accept a facility_organization argument, or
  • create a matching facility_organization for the passed facility inside this helper.

379-477: Retrieve tests validate basic permission boundaries; partial-access cases could be added later

You’re covering internal vs external orders and the with/without permission cases, including the “Cannot read delivery orders” message. That matches the new authorize_retrieve behavior.

If you ever need to exercise the “origin OR destination” semantics more explicitly, additional tests where a user has access to only one side (origin‑only or destination‑only) would make that logic harder to accidentally break, but it’s not strictly required to merge this.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd49643 and 25f9b3d.

📒 Files selected for processing (2)
  • care/emr/api/viewsets/inventory/delivery_order.py (3 hunks)
  • care/emr/tests/test_delivery_order_api.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (.cursorrules)

**/*.py: Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance).
Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).

Files:

  • care/emr/api/viewsets/inventory/delivery_order.py
  • care/emr/tests/test_delivery_order_api.py
**/tests/**/*.py

📄 CodeRabbit inference engine (.cursorrules)

Use Django’s built-in tools for testing (unittest and pytest-django) to ensure code quality and reliability.

Files:

  • care/emr/tests/test_delivery_order_api.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: rithviknishad
Repo: ohcnetwork/care PR: 3176
File: care/emr/api/viewsets/inventory/product_knowledge.py:33-40
Timestamp: 2025-07-30T12:06:18.804Z
Learning: In EMR viewsets using EMRUpsertMixin, the upsert method properly handles authorization by delegating to handle_update() and handle_create(), which in turn call authorize_update() and authorize_create() respectively. No separate authorize_upsert() method is needed.
🧬 Code graph analysis (2)
care/emr/api/viewsets/inventory/delivery_order.py (3)
care/emr/api/viewsets/inventory/request_order.py (1)
  • authorize_location_read (71-78)
care/emr/api/viewsets/inventory/supply_delivery.py (1)
  • authorize_location_read (140-147)
care/emr/api/viewsets/inventory/dispense_order.py (1)
  • authorize_location_read (54-57)
care/emr/tests/test_delivery_order_api.py (4)
care/emr/models/location.py (2)
  • FacilityLocation (12-127)
  • FacilityLocationOrganization (130-143)
care/emr/resources/inventory/supply_delivery/delivery_order.py (1)
  • SupplyDeliveryOrderStatusOptions (18-24)
care/security/permissions/supply_delivery.py (1)
  • SupplyDeliveryPermissions (16-37)
care/utils/tests/base.py (4)
  • CareAPITestBase (22-128)
  • create_facility_organization (46-49)
  • create_role_with_permissions (58-71)
  • attach_role_facility_organization_user (112-115)
🪛 Ruff (0.14.4)
care/emr/api/viewsets/inventory/delivery_order.py

72-72: Avoid specifying long messages outside the exception class

(TRY003)


81-81: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test / Test
🔇 Additional comments (4)
care/emr/api/viewsets/inventory/delivery_order.py (1)

67-83: Updated error messages look correct and consistent

The switched messages to "Cannot list/write delivery orders" match the domain language and the expectations in the new tests. The authorization wiring still mirrors the other inventory viewsets, so behavior is preserved apart from the wording change.

care/emr/tests/test_delivery_order_api.py (3)

71-200: Create‑flow tests are thorough and aligned with the viewset behavior

The create tests cover internal vs external orders, superuser vs permissioned vs unpermissioned users, and the cross‑facility origin/destination validation. Assertions on the exact error messages for forbidden writes and mismatched facilities line up with the viewset changes and should catch regressions nicely.


203-376: Update‑flow tests give good coverage for internal/external + permissions

The update tests mirror the create cases (internal/external, superuser, permissioned, unpermissioned) and validate both success paths and the “Cannot write delivery orders” failure. This lines up with authorize_update’s origin/destination ownership rules, so you’ve got solid guard rails here.


558-888: Filter and hierarchy tests give strong coverage of list behavior

The origin/destination filters, include_children, origin_isnull, and supplier/status combinations are all exercised with both positive and negative cases. That aligns nicely with DeliveryOrderFilters and filter_location_queryset, and should keep any future refactors of the filtering logic honest.

Comment on lines +481 to +557
def test_list_delivery_orders_as_superuser(self):
"""Test listing delivery orders as superuser"""
delivery_order1 = self.create_delivery_order(
origin=self.origin,
destination=self.destination,
)
delivery_order2 = self.create_delivery_order(
supplier=self.supplier,
destination=self.destination,
)
self.client.force_authenticate(user=self.superuser)
url = self.generate_base_url(self.facility.external_id)
response = self.client.get(url, format="json")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
self.assertIn(
str(delivery_order1.external_id),
[order["id"] for order in response.data["results"]],
)
self.assertIn(
str(delivery_order2.external_id),
[order["id"] for order in response.data["results"]],
)

def test_list_delivery_orders_as_user_with_permission(self):
"""Test listing delivery orders as a user with permission"""
delivery_order1 = self.create_delivery_order(
origin=self.origin,
destination=self.destination,
)
delivery_order2 = self.create_delivery_order(
supplier=self.supplier,
destination=self.destination,
)
self.client.force_authenticate(user=self.user)
self.attach_role_facility_organization_user(
role=self.role,
facility_organization=self.facility_organization,
user=self.user,
)
url = self.generate_base_url(self.facility.external_id)
response = self.client.get(url, format="json")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
self.assertIn(
str(delivery_order1.external_id),
[order["id"] for order in response.data["results"]],
)
self.assertIn(
str(delivery_order2.external_id),
[order["id"] for order in response.data["results"]],
)

def test_list_delivery_orders_as_user_without_permission(self):
"""Test listing delivery orders as a user without permission without filters"""
delivery_order1 = self.create_delivery_order(
origin=self.origin,
destination=self.destination,
)
delivery_order2 = self.create_delivery_order(
supplier=self.supplier,
destination=self.destination,
)
self.client.force_authenticate(user=self.user)
url = self.generate_base_url(self.facility.external_id)
response = self.client.get(url, format="json")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
self.assertIn(
str(delivery_order1.external_id),
[order["id"] for order in response.data["results"]],
)
self.assertIn(
str(delivery_order2.external_id),
[order["id"] for order in response.data["results"]],
)

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

List tests mix response shape and permission expectations; tighten assertions

Two small things here:

  1. In the “list as superuser / user with permission / user without permission” tests you assert len(response.data) == 2 and then index response.data["results"]. That length check is really asserting the number of top‑level keys, not the number of orders. If the intention is to assert the number of returned orders, it would be more robust to check either:

    • len(response.data["results"]), or
    • a dedicated count field, if present.
  2. test_list_delivery_orders_as_user_without_permission asserts a 200 with both orders visible to a user with no delivery‑related permissions. That matches the current viewset (no permission check when no origin/destination filter is applied), but it’s a fairly permissive behavior for inventory data. Just double‑check that this is explicitly desired and not an accidental gap in authorization policy.

Neither of these blocks the PR, but they’re worth a quick confirm so future readers don’t have to reverse‑engineer the intent.


🏁 Script executed:

#!/bin/bash
# Optional: search for other list tests in this repo to see how list responses are usually asserted,
# and whether open list access without explicit permissions is a common pattern.

rg -n "test_list_.*delivery" -S
rg -n "results\]\"" -S care/emr/tests

Length of output: 1787


Let me gather more information to verify the concerns.

Now let me inspect the actual test file and viewset to understand the response structure and permissions logic.


🏁 Script executed:

#!/bin/bash
# Examine the test file and view its actual response handling
cd /tmp && \
cat care/emr/tests/test_delivery_order_api.py | sed -n '481,600p'

Length of output: 73


🏁 Script executed:

#!/bin/bash
# Find the viewset for delivery orders
fd -e py -type f | xargs grep -l "DeliveryOrderViewSet" | head -5

Length of output: 170


🏁 Script executed:

#!/bin/bash
# Search for the response structure assertion more carefully
rg -n "response\.data\[" care/emr/tests/test_delivery_order_api.py -A2 -B2

Length of output: 10463


🏁 Script executed:

#!/bin/bash
# Look for pagination configuration in settings or viewset
rg -n "pagination\|PAGINATION" care/emr --type=py | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for permission checks in delivery order related code
rg -n "permission\|has_perm" care/emr --type=py -l

Length of output: 0


Fix assertion pattern for order counts and clarify permission behavior

Both concerns are verified:

  1. Lines 493, 494, 495: The three "list as..." tests incorrectly assert len(response.data) == 2, checking top-level dict keys instead of the order count. All other list tests in the file use len(response.data["results"]) instead. Change to:

    • self.assertEqual(len(response.data["results"]), 2)
  2. Lines 534–557 (test_list_delivery_orders_as_user_without_permission): This test grants 200 + full visibility to an unpermuted user on unfiltered requests, while other tests show that filtered requests from unpermitted users get 403 + "Cannot list delivery orders" (e.g., line 596). This inconsistency should be intentional—confirm the viewset logic allows unfiltered list access without permissions, or tighten it to require explicit permission regardless of filters.

🤖 Prompt for AI Agents
In care/emr/tests/test_delivery_order_api.py around lines 481-557, update the
three "list" tests so they assert the number of returned orders correctly by
using self.assertEqual(len(response.data["results"]), 2) instead of
self.assertEqual(len(response.data), 2); additionally, make permission behavior
consistent by changing test_list_delivery_orders_as_user_without_permission to
expect the same denied response as other filtered-unpermitted cases (assert
response.status_code == 403 and assert the error message contains "Cannot list
delivery orders") so the test matches the viewset's requirement that listing
requires explicit permission.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants