-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
2962: CAN Summary Card - update funding summary endpoint #3075
base: main
Are you sure you want to change the base?
Changes from all commits
7b3f3b8
894596a
a884a3b
e68f1d6
b7f1898
e61e48c
2dbe997
b1b033c
946f834
9258d2a
c555b06
cb42a46
f25ece4
7db63b3
cac3dbf
f06e1ff
a633d3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,74 @@ | ||
from flask import Response, request | ||
|
||
from marshmallow import ValidationError | ||
from models.base import BaseModel | ||
from ops_api.ops.auth.auth_types import Permission, PermissionType | ||
from ops_api.ops.auth.decorators import is_authorized | ||
from ops_api.ops.base_views import BaseItemAPI | ||
from ops_api.ops.utils.cans import get_can_funding_summary | ||
from ops_api.ops.schemas.can_funding_summary import GetCANFundingSummaryResponseSchema | ||
from ops_api.ops.utils.cans import aggregate_funding_summaries, get_can_funding_summary, get_filtered_cans | ||
from ops_api.ops.utils.response import make_response_with_headers | ||
|
||
|
||
class CANFundingSummaryItemAPI(BaseItemAPI): | ||
class CANFundingSummaryListAPI(BaseItemAPI): | ||
def __init__(self, model: BaseModel): | ||
super().__init__(model) | ||
|
||
@is_authorized(PermissionType.GET, Permission.CAN) | ||
def get(self, id: int) -> Response: | ||
def get(self) -> Response: | ||
# Get query parameters | ||
can_ids = request.args.getlist("can_ids") | ||
fiscal_year = request.args.get("fiscal_year") | ||
can = self._get_item(id) | ||
active_period = request.args.getlist("active_period", type=int) | ||
transfer = request.args.getlist("transfer") | ||
portfolio = request.args.getlist("portfolio") | ||
fy_budget = request.args.getlist("fy_budget", type=int) | ||
|
||
# Ensure required 'can_ids' parameter is provided | ||
if not can_ids: | ||
return make_response_with_headers({"error": "'can_ids' parameter is required"}, 400) | ||
|
||
# When 'can_ids' is 0 (all CANS) | ||
if can_ids == ["0"]: | ||
cans = self._get_all_items() | ||
return self._apply_filters_and_return(cans, fiscal_year, active_period, transfer, portfolio, fy_budget) | ||
|
||
# Single 'can_id' without additional filters | ||
if len(can_ids) == 1 and not (active_period or transfer or portfolio or fy_budget): | ||
return self._handle_single_can_no_filters(can_ids[0], fiscal_year) | ||
|
||
# Multiple 'can_ids' with filters | ||
cans = [self._get_item(can_id) for can_id in can_ids] | ||
return self._apply_filters_and_return(cans, fiscal_year, active_period, transfer, portfolio, fy_budget) | ||
|
||
def _handle_single_can_no_filters(self, can_id: str, fiscal_year: str = None) -> Response: | ||
can = self._get_item(can_id) | ||
can_funding_summary = get_can_funding_summary(can, int(fiscal_year) if fiscal_year else None) | ||
return make_response_with_headers(can_funding_summary) | ||
return self._create_can_funding_budget_response(can_funding_summary) | ||
|
||
def _apply_filters_and_return( | ||
self, | ||
cans: list, | ||
fiscal_year: str = None, | ||
active_period: list = None, | ||
transfer: list = None, | ||
portfolio: list = None, | ||
fy_budget: list = None, | ||
) -> Response: | ||
cans_with_filters = get_filtered_cans( | ||
cans, int(fiscal_year) if fiscal_year else None, active_period, transfer, portfolio, fy_budget | ||
) | ||
can_funding_summaries = [ | ||
get_can_funding_summary(can, int(fiscal_year) if fiscal_year else None) for can in cans_with_filters | ||
] | ||
aggregated_summary = aggregate_funding_summaries(can_funding_summaries) | ||
return self._create_can_funding_budget_response(aggregated_summary) | ||
|
||
@staticmethod | ||
def _create_can_funding_budget_response(result) -> Response: | ||
try: | ||
schema = GetCANFundingSummaryResponseSchema(many=False) | ||
result = schema.dump(result) | ||
return make_response_with_headers(result) | ||
except ValidationError as e: | ||
return make_response_with_headers({"Validation Error": str(e)}, 500) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from marshmallow import Schema, fields | ||
from ops_api.ops.schemas.cans import BasicCANSchema | ||
|
||
|
||
class CANSFundingSourceSchema(Schema): | ||
can = fields.Nested(BasicCANSchema()) | ||
carry_forward_label = fields.String(allow_none=True) | ||
expiration_date = fields.String(allow_none=True) | ||
|
||
|
||
class GetCANFundingSummaryResponseSchema(Schema): | ||
available_funding = fields.String(allow_none=True) | ||
cans = fields.List(fields.Nested(CANSFundingSourceSchema), default=[]) | ||
carry_forward_funding = fields.String(allow_none=True) | ||
received_funding = fields.String(allow_none=True) | ||
expected_funding = fields.String(allow_none=True) | ||
in_draft_funding = fields.String(allow_none=True) | ||
in_execution_funding = fields.String(allow_none=True) | ||
obligated_funding = fields.String(allow_none=True) | ||
planned_funding = fields.String(allow_none=True) | ||
total_funding = fields.String(allow_none=True) | ||
new_funding = fields.String(allow_none=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,13 +11,13 @@ | |
AZURE_SAS_TOKEN_VIEW_FUNC, | ||
BUDGET_LINE_ITEMS_ITEM_API_VIEW_FUNC, | ||
BUDGET_LINE_ITEMS_LIST_API_VIEW_FUNC, | ||
CAN_FUNDING_RECEIVED_ITEM_API_VIEW_FUNC, | ||
CAN_FUNDING_RECEIVED_LIST_API_VIEW_FUNC, | ||
CAN_FUNDING_BUDGET_ITEM_API_VIEW_FUNC, | ||
CAN_FUNDING_BUDGET_LIST_API_VIEW_FUNC, | ||
CAN_FUNDING_DETAILS_ITEM_API_VIEW_FUNC, | ||
CAN_FUNDING_DETAILS_LIST_API_VIEW_FUNC, | ||
CAN_FUNDING_SUMMARY_ITEM_API_VIEW_FUNC, | ||
CAN_FUNDING_RECEIVED_ITEM_API_VIEW_FUNC, | ||
CAN_FUNDING_RECEIVED_LIST_API_VIEW_FUNC, | ||
CAN_FUNDING_SUMMARY_LIST_API_VIEW_FUNC, | ||
CAN_ITEM_API_VIEW_FUNC, | ||
CAN_LIST_API_VIEW_FUNC, | ||
CANS_BY_PORTFOLIO_API_VIEW_FUNC, | ||
|
@@ -172,8 +172,8 @@ def register_api(api_bp: Blueprint) -> None: | |
) | ||
|
||
api_bp.add_url_rule( | ||
"/can-funding-summary/<int:id>", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The endpoints for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great catch! I changed the view name to |
||
view_func=CAN_FUNDING_SUMMARY_ITEM_API_VIEW_FUNC, | ||
"/can-funding-summary", | ||
view_func=CAN_FUNDING_SUMMARY_LIST_API_VIEW_FUNC, | ||
) | ||
api_bp.add_url_rule( | ||
"/portfolio-funding-summary/<int:id>", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above
request.args
handling andcan_ids
validation would be better in a Marshmallow schema but it would be acceptable to take that as a tech debt item if you don't have time to implement it.