Skip to content

Commit

Permalink
Merge pull request #3344 from HHS/OPS-3343/funding-partner
Browse files Browse the repository at this point in the history
Ops 3343/funding partner
  • Loading branch information
johndeange authored Jan 27, 2025
2 parents a3f20bd + 93016dd commit 79403cc
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 116 deletions.
10 changes: 1 addition & 9 deletions backend/data_tools/data/portfolio_data.json5
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@
{ // 8
name: "Data Governance",
abbreviation: "DG",
division_id: 6,
division_id: 9,
status: "IN_PROCESS",
team_leaders: [
{
Expand Down Expand Up @@ -285,14 +285,6 @@
description: "",
},
{ // 11
name: "Data Governance",
abbreviation: "DG",
division_id: 9,
status: "IN_PROCESS",
team_leaders: [],
description: "",
},
{ // 12
name: "Not A Specific Portfolio",
abbreviation: "NON-OPRE",
division_id: 3,
Expand Down
5 changes: 2 additions & 3 deletions backend/data_tools/initial_data/007-portfolio.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, descript
Federal investment in home visiting — and related research and evaluation — has greatly expanded through the Maternal, Infant, and Early Childhood Home Visiting (MIECHV) Program, which was established in 2010. The MIECHV Program supports home visiting for expectant and new parents with children up to kindergarten entry age who live in communities that are at-risk for poor maternal and child health outcomes. Families choose to participate in home visiting programs, and partner with health, social service, and child development professionals to set and achieve goals that improve their health and well-being. MIECHV is administered by the Health Resources and Services Administration (HRSA) in collaboration with ACF. HRSA oversees the state and territory MIECHV Program, which provides grants to states, territories, and eligible non-profit organizations to develop and implement statewide home visiting programs. ACF oversees the Tribal MIECHV program, which provides grants to tribes, tribal organizations, and Urban Indian Organizations to develop, implement, and evaluate home visiting programs in American Indian and Alaska Native communities.

In collaboration with HRSA and with ACF’s Tribal MIECHV program, ACF’s Office of Planning, Research, and Evaluation manages and partners on research, evaluation, and technical assistance activities related to MIECHV and home visiting. ', current_timestamp, current_timestamp);
INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, description, created_on, updated_on) VALUES (8, 'Data Governance', 'DG', 'IN_PROCESS', 6, e' Data governance is the mechanism (i.e., structures, processes, and policies) for organizational staff and leadership to manage data throughout the data lifecycle, while ensuring its security, exploring opportunities to share data for evidence-building activities, and using data for programmatic, evaluation and research purposes. ACF’s goals related to data governance are to make data more usable, accessible, and protected to meet the operational and evidence-building data governance needs of ACF; meet the operational and evidence-building data governance needs of ACF offices; and promote the reuse of ACF data for evidence-building purposes at the state, local, tribal, territory, and grant recipient levels.
INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, description, created_on, updated_on) VALUES (8, 'Data Governance', 'DG', 'IN_PROCESS', 9, e' Data governance is the mechanism (i.e., structures, processes, and policies) for organizational staff and leadership to manage data throughout the data lifecycle, while ensuring its security, exploring opportunities to share data for evidence-building activities, and using data for programmatic, evaluation and research purposes. ACF’s goals related to data governance are to make data more usable, accessible, and protected to meet the operational and evidence-building data governance needs of ACF; meet the operational and evidence-building data governance needs of ACF offices; and promote the reuse of ACF data for evidence-building purposes at the state, local, tribal, territory, and grant recipient levels.

The Data Governance Team within DDI has primary responsibility for coordinating ACF\'s data governance activities. For the purpose of OPS, this portfolio covers projects that advance ACF’s progress in meeting its data governance goals. This portfolio is led by the OPRE Division of Data and Improvement. ', current_timestamp, current_timestamp);
INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, description, created_on, updated_on) VALUES (9, 'Office Of The Director', 'OD', 'IN_PROCESS', 3, '', current_timestamp, current_timestamp);
INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, description, created_on, updated_on) VALUES (10, 'Privacy & Security', 'PS', 'IN_PROCESS', 8, '', current_timestamp, current_timestamp);
INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, description, created_on, updated_on) VALUES (11, 'Data Governance', 'DG', 'IN_PROCESS', 9, '', current_timestamp, current_timestamp);
INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, description, created_on, updated_on) VALUES (12, 'Not A Specific Portfolio', 'NON-OPRE', 'IN_PROCESS', 3, '', current_timestamp, current_timestamp);
INSERT INTO ops.portfolio (id, name, abbreviation, status, division_id, description, created_on, updated_on) VALUES (11, 'Not A Specific Portfolio', 'NON-OPRE', 'IN_PROCESS', 3, '', current_timestamp, current_timestamp);
5 changes: 2 additions & 3 deletions backend/data_tools/initial_data/008-portfolio_version.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id,
Federal investment in home visiting — and related research and evaluation — has greatly expanded through the Maternal, Infant, and Early Childhood Home Visiting (MIECHV) Program, which was established in 2010. The MIECHV Program supports home visiting for expectant and new parents with children up to kindergarten entry age who live in communities that are at-risk for poor maternal and child health outcomes. Families choose to participate in home visiting programs, and partner with health, social service, and child development professionals to set and achieve goals that improve their health and well-being. MIECHV is administered by the Health Resources and Services Administration (HRSA) in collaboration with ACF. HRSA oversees the state and territory MIECHV Program, which provides grants to states, territories, and eligible non-profit organizations to develop and implement statewide home visiting programs. ACF oversees the Tribal MIECHV program, which provides grants to tribes, tribal organizations, and Urban Indian Organizations to develop, implement, and evaluate home visiting programs in American Indian and Alaska Native communities.

In collaboration with HRSA and with ACF’s Tribal MIECHV program, ACF’s Office of Planning, Research, and Evaluation manages and partners on research, evaluation, and technical assistance activities related to MIECHV and home visiting. ', current_timestamp, current_timestamp, 1, null, 0);
INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id, description, created_on, updated_on, transaction_id, end_transaction_id, operation_type) VALUES (8, 'Data Governance', 'DG', 'IN_PROCESS', 6, e' Data governance is the mechanism (i.e., structures, processes, and policies) for organizational staff and leadership to manage data throughout the data lifecycle, while ensuring its security, exploring opportunities to share data for evidence-building activities, and using data for programmatic, evaluation and research purposes. ACF’s goals related to data governance are to make data more usable, accessible, and protected to meet the operational and evidence-building data governance needs of ACF; meet the operational and evidence-building data governance needs of ACF offices; and promote the reuse of ACF data for evidence-building purposes at the state, local, tribal, territory, and grant recipient levels.
INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id, description, created_on, updated_on, transaction_id, end_transaction_id, operation_type) VALUES (8, 'Data Governance', 'DG', 'IN_PROCESS', 9, e' Data governance is the mechanism (i.e., structures, processes, and policies) for organizational staff and leadership to manage data throughout the data lifecycle, while ensuring its security, exploring opportunities to share data for evidence-building activities, and using data for programmatic, evaluation and research purposes. ACF’s goals related to data governance are to make data more usable, accessible, and protected to meet the operational and evidence-building data governance needs of ACF; meet the operational and evidence-building data governance needs of ACF offices; and promote the reuse of ACF data for evidence-building purposes at the state, local, tribal, territory, and grant recipient levels.

The Data Governance Team within DDI has primary responsibility for coordinating ACF\'s data governance activities. For the purpose of OPS, this portfolio covers projects that advance ACF’s progress in meeting its data governance goals. This portfolio is led by the OPRE Division of Data and Improvement. ', current_timestamp, current_timestamp, 1, null, 0);
INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id, description, created_on, updated_on, transaction_id, end_transaction_id, operation_type) VALUES (9, 'Office Of The Director', 'OD', 'IN_PROCESS', 3, '', current_timestamp, current_timestamp, 1, null, 0);
INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id, description, created_on, updated_on, transaction_id, end_transaction_id, operation_type) VALUES (10, 'Privacy & Security', 'PS', 'IN_PROCESS', 8, '', current_timestamp, current_timestamp, 1, null, 0);
INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id, description, created_on, updated_on, transaction_id, end_transaction_id, operation_type) VALUES (11, 'Data Governance', 'DG', 'IN_PROCESS', 9, '', current_timestamp, current_timestamp, 1, null, 0);
INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id, description, created_on, updated_on, transaction_id, end_transaction_id, operation_type) VALUES (12, 'Not A Specific Portfolio', 'NON-OPRE', 'IN_PROCESS', 3, '', current_timestamp, current_timestamp, 1, null, 0);
INSERT INTO ops.portfolio_version (id, name, abbreviation, status, division_id, description, created_on, updated_on, transaction_id, end_transaction_id, operation_type) VALUES (11, 'Not A Specific Portfolio', 'NON-OPRE', 'IN_PROCESS', 3, '', current_timestamp, current_timestamp, 1, null, 0);
2 changes: 1 addition & 1 deletion backend/data_tools/src/import_static_data/import_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def after_user_load(conn: Connection) -> None:
" where deputy_division_director_id is null;"
"update ops.division "
" set division_director_id = (select id from ops.ops_user where email = '[email protected]') "
" where id = 6;"
" where id = 9;"
)
session.execute(text(stmt))
session.commit()
Expand Down
88 changes: 53 additions & 35 deletions backend/data_tools/src/load_cans/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from csv import DictReader
from dataclasses import dataclass
from typing import List
from dataclasses import dataclass, field
from typing import List, Optional

from loguru import logger
from sqlalchemy import and_, select
Expand All @@ -14,21 +14,23 @@ class CANData:
"""
Dataclass to represent a CAN data row.
"""
SYS_CAN_ID: int

CAN_NBR: str
CAN_DESCRIPTION: str
FUND: str
ALLOWANCE: str
ALLOTMENT_ORG: str
SUB_ALLOWANCE: str
CURRENT_FY_FUNDING_YTD: float
APPROP_PREFIX: str
APPROP_POSTFIX: str
APPROP_YEAR: str
PORTFOLIO: str
FUNDING_SOURCE: str
METHOD_OF_TRANSFER: str
NICK_NAME: str
SYS_CAN_ID: Optional[int] = field(default=None)
CAN_DESCRIPTION: Optional[str] = field(default=None)
ALLOWANCE: Optional[str] = field(default=None)
ALLOTMENT_ORG: Optional[str] = field(default=None)
SUB_ALLOWANCE: Optional[str] = field(default=None)
CURRENT_FY_FUNDING_YTD: Optional[float] = field(default=None)
APPROP_PREFIX: Optional[str] = field(default=None)
APPROP_POSTFIX: Optional[str] = field(default=None)
APPROP_YEAR: Optional[str] = field(default=None)
FUNDING_SOURCE: Optional[str] = field(default=None)
METHOD_OF_TRANSFER: Optional[str] = field(default=None)
NICK_NAME: Optional[str] = field(default=None)
FUNDING_PARTNER: Optional[str] = field(default=None)

def __post_init__(self):
if not self.CAN_NBR:
Expand All @@ -45,10 +47,11 @@ def __post_init__(self):
self.APPROP_PREFIX = str(self.APPROP_PREFIX) if self.APPROP_PREFIX else None
self.APPROP_POSTFIX = str(self.APPROP_POSTFIX) if self.APPROP_POSTFIX else None
self.APPROP_YEAR = str(self.APPROP_YEAR) if self.APPROP_YEAR else None
self.PORTFOLIO = str(self.PORTFOLIO) if self.PORTFOLIO else None
self.PORTFOLIO = str(self.PORTFOLIO).upper() if self.PORTFOLIO else None
self.FUNDING_SOURCE = str(self.FUNDING_SOURCE) if self.FUNDING_SOURCE else None
self.METHOD_OF_TRANSFER = str(self.METHOD_OF_TRANSFER) if self.METHOD_OF_TRANSFER else None
self.METHOD_OF_TRANSFER = str(self.METHOD_OF_TRANSFER).upper() if self.METHOD_OF_TRANSFER else None
self.NICK_NAME = str(self.NICK_NAME) if self.NICK_NAME else None
self.FUNDING_PARTNER = str(self.FUNDING_PARTNER) if self.FUNDING_PARTNER else None


def create_can_data(data: dict) -> CANData:
Expand All @@ -61,6 +64,7 @@ def create_can_data(data: dict) -> CANData:
"""
return CANData(**data)


def validate_data(data: CANData) -> bool:
"""
Validate the data in a CanData instance.
Expand All @@ -69,12 +73,15 @@ def validate_data(data: CANData) -> bool:
:return: True if the data is valid, False otherwise.
"""
return all([
data.CAN_NBR is not None,
data.PORTFOLIO is not None,
data.FUNDING_SOURCE is not None,
data.METHOD_OF_TRANSFER is not None,
])
return all(
[
data.CAN_NBR is not None,
data.PORTFOLIO is not None,
data.FUNDING_SOURCE is not None,
data.METHOD_OF_TRANSFER is not None,
]
)


def validate_all(data: List[CANData]) -> bool:
"""
Expand All @@ -86,6 +93,7 @@ def validate_all(data: List[CANData]) -> bool:
"""
return sum(1 for d in data if validate_data(d)) == len(data)


def create_models(data: CANData, sys_user: User, session: Session) -> None:
"""
Create and persist the CAN and CANFundingDetails models.
Expand All @@ -106,7 +114,9 @@ def create_models(data: CANData, sys_user: User, session: Session) -> None:
logger.debug(f"Creating models for {data}")

try:
portfolio = session.execute(select(Portfolio).where(Portfolio.abbreviation == data.PORTFOLIO)).scalar_one_or_none()
portfolio = session.execute(
select(Portfolio).where(Portfolio.abbreviation == data.PORTFOLIO)
).scalar_one_or_none()
if not portfolio:
raise ValueError(f"Portfolio not found for {data.PORTFOLIO}")

Expand Down Expand Up @@ -153,18 +163,25 @@ def get_or_create_funding_details(data: CANData, sys_user: User, session: Sessio
appropriation = "-".join([data.APPROP_PREFIX or "", appropriation_year, data.APPROP_POSTFIX or ""])

method_of_transfer = CANMethodOfTransfer[data.METHOD_OF_TRANSFER]
funding_source = CANFundingSource[data.FUNDING_SOURCE]
existing_funding_details = session.execute(select(CANFundingDetails).where(
and_(
CANFundingDetails.fiscal_year == fiscal_year,
CANFundingDetails.fund_code == fund_code,
CANFundingDetails.allowance == allowance,
CANFundingDetails.sub_allowance == sub_allowance,
CANFundingDetails.allotment == allotment,
CANFundingDetails.appropriation == appropriation,
CANFundingDetails.method_of_transfer == method_of_transfer,
CANFundingDetails.funding_source == funding_source,
))).scalar_one_or_none()
funding_source = (
CANFundingSource[data.FUNDING_SOURCE] if data.FUNDING_SOURCE != "ACF - MOU" else CANFundingSource.ACF_MOU
)
funding_partner = data.FUNDING_PARTNER
existing_funding_details = session.execute(
select(CANFundingDetails).where(
and_(
CANFundingDetails.fiscal_year == fiscal_year,
CANFundingDetails.fund_code == fund_code,
CANFundingDetails.allowance == allowance,
CANFundingDetails.sub_allowance == sub_allowance,
CANFundingDetails.allotment == allotment,
CANFundingDetails.appropriation == appropriation,
CANFundingDetails.method_of_transfer == method_of_transfer,
CANFundingDetails.funding_source == funding_source,
CANFundingDetails.funding_partner == funding_partner,
)
)
).scalar_one_or_none()
if not existing_funding_details:
funding_details = CANFundingDetails(
fiscal_year=fiscal_year,
Expand All @@ -175,6 +192,7 @@ def get_or_create_funding_details(data: CANData, sys_user: User, session: Sessio
appropriation=appropriation,
method_of_transfer=method_of_transfer,
funding_source=funding_source,
funding_partner=funding_partner,
created_by=sys_user.id,
)
return funding_details
Expand Down
Loading

0 comments on commit 79403cc

Please sign in to comment.