feat: OPS-1639 PR2 - Budget Team Requisition Review Card#5634
Conversation
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Implements OPS-1639 PR2 support for Budget Team “For Review” work by adding a new backend endpoint to fetch pending pre-award requisition tasks (DD-approved, requisition not yet entered) and a new frontend review card surfaced in the Change Requests “For Review” tab, including updated total-count logic and mocks/tests.
Changes:
- Backend: add
GET /api/v1/procurement-tracker-steps/pending-requisitions/, service query, and schema support to include agreement + budget line item data. - Frontend: add
useGetPendingBudgetRequisitionsQuery, renderBudgetTeamRequisitionReviewCardin the review list, and include budget requisitions in the overall review-count hook. - Tests/mocks: MSW handler for the new endpoint plus new/updated unit tests.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/mocks/handlers.js | Adds MSW mock for pending budget requisitions endpoint. |
| frontend/src/hooks/useChangeRequests.hooks.test.js | Updates hook tests to account for the new pending budget requisitions query. |
| frontend/src/hooks/useChangeRequests.hooks.js | Includes pending budget requisitions in the total “items needing review” count. |
| frontend/src/components/ChangeRequests/PreAwardReviewCard/PreAwardReviewCard.jsx | Adds clarification comment about not using the shared ReviewCard base component. |
| frontend/src/components/ChangeRequests/ChangeRequestsList/ChangeRequestsList.jsx | Fetches and renders budget requisition review cards and updates loading/error handling. |
| frontend/src/components/ChangeRequests/ChangeRequestsList/ChangeRequestList.test.jsx | Updates list tests to mock the new query. |
| frontend/src/components/ChangeRequests/BudgetTeamRequisitionReviewCard/index.js | Exports the new card component. |
| frontend/src/components/ChangeRequests/BudgetTeamRequisitionReviewCard/BudgetTeamRequisitionReviewCard.test.jsx | Adds unit tests for the new budget team requisition review card. |
| frontend/src/components/ChangeRequests/BudgetTeamRequisitionReviewCard/BudgetTeamRequisitionReviewCard.jsx | Introduces the UI component for budget team requisition review tasks. |
| frontend/src/api/opsAPI.js | Adds RTK Query endpoint/hook for pending budget requisitions. |
| backend/ops_api/tests/ops/procurement_tracker/test_budget_team_requisition_review_card.py | Adds backend tests for the new pending requisitions endpoint. |
| backend/ops_api/ops/views.py | Registers the pending requisitions view function. |
| backend/ops_api/ops/urls.py | Adds URL rule for /procurement-tracker-steps/pending-requisitions/. |
| backend/ops_api/ops/services/procurement_tracker_steps.py | Adds notification link and implements get_pending_requisitions_for_user (but currently introduces a regression in pending approvals). |
| backend/ops_api/ops/schemas/procurement_tracker_steps.py | Extends nested agreement schema to include budget line items and agreement total. |
| backend/ops_api/ops/resources/procurement_tracker_steps.py | Adds API resource class for pending requisitions list endpoint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| # For all other users, allow access when they are the division director/deputy | ||
| # for the related agreement. This keeps the pending approvals list aligned | ||
| # with reviewer notification recipients. |
| ) | ||
| loaded_db.add(step_4) | ||
| else: | ||
| step_4.status = ProcurementTrackerStepStatus.COMPLETED | ||
| loaded_db.commit() |
| @@ -112,6 +115,7 @@ describe("ChangeRequestList", () => { | |||
| }); | |||
|
|
|||
| useGetChangeRequestsListQuery.mockReturnValue({ data: undefined, isLoading: false, isError: false }); | |||
There was a problem hiding this comment.
This review was generated by claude and I went in to manually verify concerns just to double check.
Backend Analysis
API Resource (ops/resources/procurement_tracker_steps.py)
New endpoint: GET /api/v1/procurement-tracker-steps/pending-requisitions/
Strengths:
- ✅ Follows existing pattern (PendingApprovalsAPI)
- ✅ Proper authorization with @is_authorized decorator
- ✅ User validation with clear 401 response
- ✅ Good logging for debugging
Issues:
⚠️ Authorization scope mismatch (line 164):
@is_authorized(PermissionType.GET, Permission.AGREEMENT)- This uses generic GET permission on AGREEMENT. Should this be a more specific permission like Permission.PROCUREMENT_TRACKER_STEP or a new
GET_PENDING_REQUISITIONS scope? The role-based filtering happens in the service layer, but the authorization decorator should match the actual
permission model. - Minor: Redundant user check (line 166-168):
The hasattr(current_user, "id") check is defensive but likely unnecessary if get_current_user() is reliable. Consider whether this should be
an assertion or if it's needed at all.
Service Layer (ops/services/procurement_tracker_steps.py)
Method: get_pending_requisitions_for_user(user_id)
Strengths:
- ✅ Clear docstring with filter criteria
- ✅ Role-based filtering (BUDGET_TEAM only)
- ✅ Proper eager loading with selectinload to avoid N+1 queries
- ✅ Correct query conditions for "DD approved, requisition not entered"
- ✅ Orders by pre_award_approval_responded_date (most recent first)
Issues:
- 🔴 Critical: Import placement (line 790-795):
from sqlalchemy import and_
from models import (
Agreement,
DefaultProcurementTrackerStep,
ProcurementTracker,
)
- Local imports inside a method violate PEP 8 and project conventions. These should be at module level. This is a red flag that could
indicate circular import issues. If there's a circular dependency, it should be resolved properly, not worked around with local imports. ⚠️ Model inconsistency (line 821):
DefaultProcurementTrackerStep.pre_award_approval_status == "APPROVED"- Using string literal "APPROVED" instead of enum. Should this be ProcurementTrackerStepStatus.APPROVED or similar? Check if there's an enum
for approval status.
Schema Updates (ops/schemas/procurement_tracker_steps.py)
Strengths:
- ✅ Clean nested schema structure
- ✅ Includes date_needed field for BLI (needed for obligate-by calculation)
- ✅ Adds agreement_total as dump-only field
Minor observations:
- The NestedBudgetLineItemSchema is minimal but sufficient for card display
- Good use of dump_only=True for calculated fields
Notification Enhancement (ops/services/procurement_tracker_steps.py)
Line 510-512: Adds markdown link to notification message:
f"Review Agreement"
Strengths:
- ✅ Uses configured frontend URL
- ✅ Markdown link format for rich notifications
Issue:
⚠️ The review URL points to /agreements/{id}/review-budget-requisition which the PR description states will be "wired in PR4". This creates
a temporary dead link. Consider:- Adding a comment noting this is a placeholder for PR4
- Or deferring this notification change to PR4
Frontend Analysis
API Integration (api/opsAPI.js)
Strengths:
- ✅ Adds new Budget Requisitions tag for cache invalidation
- ✅ Follows existing RTK Query patterns
- ✅ Proper export of new hook
Component: BudgetTeamRequisitionReviewCard
Strengths:
- ✅ Excellent inline documentation explaining why it doesn't use ReviewCard base component
- ✅ Props are well-typed with PropTypes
- ✅ Uses existing design system components (Tag, FontAwesome icons)
- ✅ Consistent styling with other review cards
- ✅ Good use of custom hooks (useGetAgreementName, useGetUserFullNameFromId)
Issues:
⚠️ Button has no action (line 113-125):
<button
type="button"
className="usa-button--unstyled text-primary font-12px cursor-pointer"
data-cy="review-agreement-button"- The button has no onClick handler. Per the PR description, "navigation will be wired in PR4", but this creates a dead button. Consider:
- Adding a comment above the button noting it will be wired in PR4
- Or adding disabled attribute with a title tooltip explaining it's coming soon - Minor: Conditional rendering (line 65):
The isCondensed mode removes the header but is never used in this PR. Is this for future use? If so, consider adding a comment.
Integration: ChangeRequestsList.jsx
Strengths:
- ✅ Properly fetches budgetRequisitions data
- ✅ Error handling includes new query
- ✅ Loading states updated
- ✅ Helper functions (calculateExecutingBliCount, calculateExecutingTotal, getObligateByDate) are well-implemented
Issues:
⚠️ Magic string (line 671):
budgetLineItems.filter((bli) => bli.status === "In Execution")- String literal "In Execution" should be a constant or enum. Does the codebase have a BudgetLineItemStatus constant in JS? If not, consider
extracting to a constant. - Edge case: getObligateByDate returns ISO date string, but what if all executing BLIs have null date_needed? The function returns null,
which is correct, but ensure the card component handles this gracefully (which it does with the conditional rendering).
Hooks: useChangeRequests.hooks.js
Strengths:
- ✅ Properly includes budget requisitions in total count
- ✅ Skips query if no userId
Recommendations
Must Fix (Blocking):
- 🔴 Move local imports to module level in procurement_tracker_steps.py:790. If there's a circular dependency, resolve it properly.
Should Fix (Important):
⚠️ Replace string literals with enums/constants:
- Backend: "APPROVED" → use enum
- Frontend: "In Execution" → use constant⚠️ Review authorization permission scope - should it be Permission.PROCUREMENT_TRACKER_STEP or remain Permission.AGREEMENT?⚠️ Add comments for incomplete features:
- Button with no onClick handler (line ~113 in BudgetTeamRequisitionReviewCard.jsx)
- Notification link to non-existent page (line ~512 in procurement_tracker_steps.py)
Nice to Have:
- Consider extracting calculateExecutingBliCount, calculateExecutingTotal, getObligateByDate to a shared helper file if they'll be reused in
PR3/PR4. - The isCondensed prop on the card is never used - either use it or remove it in this PR.
Summary
Overall assessment: This is a solid, well-structured PR that follows project conventions and integrates cleanly with the existing codebase.
The implementation is straightforward and the test coverage is comprehensive.
Critical issue: The local imports in the service method must be addressed before merging.
Minor issues: String literals for statuses and incomplete feature placeholders should be documented or improved.
Once the critical import issue is resolved and string literals are replaced with constants, this PR will be ready to merge. Great work on the
clean separation between backend/frontend and the thoughtful test coverage! 🎉
The issue of imports in functions is something I've generally tried to avoid when using claude on my own as well. I think it is best practice to just place all imports in the same spot at the top of the file.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Code Review Response - PR #5634Backend AnalysisAPI Resource (ops/resources/procurement_tracker_steps.py)
|
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
@rajohnson90 Addressed the issues you caught. Thanks for the review! |
|
🎉 This PR is included in version 1.383.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
What changed
Implements the "For Review" card that displays pre-award requisition review tasks to Budget Team members after Division Director approval.
This is PR2 of the OPS-1639 feature set. PR1 (backend foundation) was completed previously.
Note: This is a clean rebased version of PR #5619 to resolve commitlint issues with duplicate commits from main.
Backend Changes
GET /api/v1/procurement-tracker-steps/pending-requisitions/get_pending_requisitions_for_user(user_id)date_neededfieldFrontend Changes
useGetPendingBudgetRequisitionsQueryBudgetTeamRequisitionReviewCardIssue
Part of OPS-1639 (Budget Team Requisition Approval)
How to test
Backend API:
Frontend Component:
Manual Testing:
A11y impact
Screenshots
N/A - Card UI follows existing design system patterns
Definition of Done Checklist
Links