This commit is contained in:
zandercymatics 2025-01-09 14:46:37 -07:00
parent bff98996e8
commit 2fa8366206
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
3 changed files with 91 additions and 97 deletions

View file

@ -80,6 +80,22 @@ class Command(BaseCommand):
else: else:
raise CommandError(f"Cannot find '{branch}' federal agencies in our database.") raise CommandError(f"Cannot find '{branch}' federal agencies in our database.")
# C901 'Command.handle' is too complex (12)
self.handle_all_populate_portfolio(agencies, parse_domains, parse_requests, both)
TerminalHelper.log_script_run_summary(
self.updated_portfolios,
self.failed_portfolios,
self.skipped_portfolios,
debug=False,
skipped_header="----- SOME PORTFOLIOS WERE SKIPPED -----",
display_as_str=True,
)
def handle_all_populate_portfolio(self, agencies, parse_domains, parse_requests, both):
"""Loops through every agency and creates a portfolio for each.
For a given portfolio, it adds suborgs, and associates
the suborg and portfolio to domains and domain requests.
"""
all_suborganizations = [] all_suborganizations = []
all_domains = [] all_domains = []
all_domain_requests = [] all_domain_requests = []
@ -87,13 +103,19 @@ class Command(BaseCommand):
message = f"Processing federal agency '{federal_agency.agency}'..." message = f"Processing federal agency '{federal_agency.agency}'..."
TerminalHelper.colorful_logger(logger.info, TerminalColors.MAGENTA, message) TerminalHelper.colorful_logger(logger.info, TerminalColors.MAGENTA, message)
try: try:
# C901 'Command.handle' is too complex (12) portfolio, created = self.create_portfolio(federal_agency)
suborgs, domains, requests = self.handle_populate_portfolio( suborganizations = self.create_suborganizations(portfolio, federal_agency)
federal_agency, parse_domains, parse_requests, both domains = []
) domain_requests = []
all_suborganizations.extend(suborgs) if created and parse_domains or both:
domains = self.handle_portfolio_domains(portfolio, federal_agency)
if parse_requests or both:
domain_requests = self.handle_portfolio_requests(portfolio, federal_agency)
all_suborganizations.extend(suborganizations)
all_domains.extend(domains) all_domains.extend(domains)
all_domain_requests.extend(requests) all_domain_requests.extend(domain_requests)
except Exception as exec: except Exception as exec:
self.failed_portfolios.add(federal_agency) self.failed_portfolios.add(federal_agency)
logger.error(exec) logger.error(exec)
@ -107,88 +129,6 @@ class Command(BaseCommand):
message = f"Added city and state_territory information to {len(all_suborganizations)} suborgs." message = f"Added city and state_territory information to {len(all_suborganizations)} suborgs."
TerminalHelper.colorful_logger(logger.info, TerminalColors.MAGENTA, message) TerminalHelper.colorful_logger(logger.info, TerminalColors.MAGENTA, message)
TerminalHelper.log_script_run_summary(
self.updated_portfolios,
self.failed_portfolios,
self.skipped_portfolios,
debug=False,
skipped_header="----- SOME PORTFOLIOS WERE SKIPPED -----",
display_as_str=True,
)
def handle_populate_portfolio(self, federal_agency, parse_domains, parse_requests, both):
"""Attempts to create a portfolio. If successful, this function will
also create new suborganizations"""
portfolio, created = self.create_portfolio(federal_agency)
suborganizations = self.create_suborganizations(portfolio, federal_agency)
domains = []
domain_requests = []
if created:
if parse_domains or both:
domains = self.handle_portfolio_domains(portfolio, federal_agency)
if parse_requests or both:
domain_requests = self.handle_portfolio_requests(portfolio, federal_agency)
return suborganizations, domains, domain_requests
def post_process_suborganization_fields(self, suborganizations, domains, requests):
"""Post-process suborganization fields by pulling data from related domains and requests.
This function updates suborganization city and state_territory fields based on
related domain information and domain request information.
"""
# Exclude domains and requests where the org name is the same,
# and where we are missing some crucial information.
domains = DomainInformation.objects.filter(id__in=[domain.id for domain in domains]).exclude(
portfolio__isnull=True,
organization_name__isnull=True,
sub_organization__isnull=True,
organization_name__iexact=F("portfolio__organization_name"),
)
domains_dict = {domain.organization_name: domain for domain in domains}
requests = DomainRequest.objects.filter(id__in=[request.id for request in requests]).exclude(
portfolio__isnull=True,
organization_name__isnull=True,
sub_organization__isnull=True,
organization_name__iexact=F("portfolio__organization_name"),
)
requests_dict = {request.organization_name: request for request in requests}
for suborg in suborganizations:
domain = domains_dict.get(suborg.name, None)
request = requests_dict.get(suborg.name, None)
# PRIORITY:
# 1. Domain info
# 2. Domain request requested suborg fields
# 3. Domain request normal fields
city = None
if domain and domain.city:
city = normalize_string(domain.city, lowercase=False)
elif request and request.suborganization_city:
city = normalize_string(request.suborganization_city, lowercase=False)
elif request and request.city:
city = normalize_string(request.city, lowercase=False)
state_territory = None
if domain and domain.state_territory:
state_territory = domain.state_territory
elif request and request.suborganization_state_territory:
state_territory = request.suborganization_state_territory
elif request and request.state_territory:
state_territory = request.state_territory
if city:
suborg.city = city
if suborg:
suborg.state_territory = state_territory
Suborganization.objects.bulk_update(suborganizations, ["city", "state_territory"])
def create_portfolio(self, federal_agency): def create_portfolio(self, federal_agency):
"""Creates a portfolio if it doesn't presently exist. """Creates a portfolio if it doesn't presently exist.
Returns portfolio, created.""" Returns portfolio, created."""
@ -278,6 +218,7 @@ class Command(BaseCommand):
) )
else: else:
TerminalHelper.colorful_logger(logger.warning, TerminalColors.YELLOW, "No suborganizations added") TerminalHelper.colorful_logger(logger.warning, TerminalColors.YELLOW, "No suborganizations added")
return new_suborgs return new_suborgs
def handle_portfolio_requests(self, portfolio: Portfolio, federal_agency: FederalAgency): def handle_portfolio_requests(self, portfolio: Portfolio, federal_agency: FederalAgency):
@ -285,14 +226,14 @@ class Command(BaseCommand):
Associate portfolio with domain requests for a federal agency. Associate portfolio with domain requests for a federal agency.
Updates all relevant domain request records. Updates all relevant domain request records.
""" """
invalid_states = [
DomainRequest.DomainRequestStatus.STARTED,
DomainRequest.DomainRequestStatus.INELIGIBLE,
DomainRequest.DomainRequestStatus.REJECTED,
]
domain_requests = DomainRequest.objects.filter(federal_agency=federal_agency, portfolio__isnull=True).exclude( domain_requests = DomainRequest.objects.filter(federal_agency=federal_agency, portfolio__isnull=True).exclude(
status__in=[ status__in=invalid_states
DomainRequest.DomainRequestStatus.STARTED,
DomainRequest.DomainRequestStatus.INELIGIBLE,
DomainRequest.DomainRequestStatus.REJECTED,
]
) )
if not domain_requests.exists(): if not domain_requests.exists():
message = f""" message = f"""
Portfolio '{portfolio}' not added to domain requests: no valid records found. Portfolio '{portfolio}' not added to domain requests: no valid records found.
@ -346,3 +287,56 @@ class Command(BaseCommand):
TerminalHelper.colorful_logger(logger.info, TerminalColors.OKGREEN, message) TerminalHelper.colorful_logger(logger.info, TerminalColors.OKGREEN, message)
return domain_infos return domain_infos
def post_process_suborganization_fields(self, suborganizations, domains, requests):
"""Post-process suborganization fields by pulling data from related domains and requests.
This function updates suborganization city and state_territory fields based on
related domain information and domain request information.
"""
domains = DomainInformation.objects.filter(id__in=[domain.id for domain in domains]).exclude(
portfolio__isnull=True,
organization_name__isnull=True,
sub_organization__isnull=True,
organization_name__iexact=F("portfolio__organization_name"),
)
requests = DomainRequest.objects.filter(id__in=[request.id for request in requests]).exclude(
portfolio__isnull=True,
organization_name__isnull=True,
sub_organization__isnull=True,
organization_name__iexact=F("portfolio__organization_name"),
)
domains_dict = {domain.organization_name: domain for domain in domains}
requests_dict = {request.organization_name: request for request in requests}
for suborg in suborganizations:
domain = domains_dict.get(suborg.name, None)
request = requests_dict.get(suborg.name, None)
# PRIORITY:
# 1. Domain info
# 2. Domain request requested suborg fields
# 3. Domain request normal fields
city = None
if domain and domain.city:
city = normalize_string(domain.city, lowercase=False)
elif request and request.suborganization_city:
city = normalize_string(request.suborganization_city, lowercase=False)
elif request and request.city:
city = normalize_string(request.city, lowercase=False)
state_territory = None
if domain and domain.state_territory:
state_territory = domain.state_territory
elif request and request.suborganization_state_territory:
state_territory = request.suborganization_state_territory
elif request and request.state_territory:
state_territory = request.state_territory
if city:
suborg.city = city
if suborg:
suborg.state_territory = state_territory
Suborganization.objects.bulk_update(suborganizations, ["city", "state_territory"])

View file

@ -60,7 +60,8 @@ class Command(BaseCommand):
# Delete data from our preset list # Delete data from our preset list
if normalized_name in extra_records_to_prune: if normalized_name in extra_records_to_prune:
# The 'keep' field expects a Suborganization but we just pass in a string, so this is just a workaround. # The 'keep' field expects a Suborganization but we just pass in a string, so this is just a workaround.
# This assumes that there is only one item in the name_group array (see usda/oc example). Should be fine, given our data. # This assumes that there is only one item in the name_group array (see usda/oc example).
# But this should be fine, given our data.
hardcoded_record_name = extra_records_to_prune[normalized_name]["replace_with"] hardcoded_record_name = extra_records_to_prune[normalized_name]["replace_with"]
name_group = name_groups.get(normalize_string(hardcoded_record_name)) name_group = name_groups.get(normalize_string(hardcoded_record_name))
keep = name_group[0] if name_group else None keep = name_group[0] if name_group else None

View file

@ -1,5 +1,4 @@
import copy import copy
from io import StringIO
import boto3_mocking # type: ignore import boto3_mocking # type: ignore
from datetime import date, datetime, time from datetime import date, datetime, time
from django.core.management import call_command from django.core.management import call_command
@ -1746,7 +1745,7 @@ class TestCreateFederalPortfolio(TestCase):
self.domain_info.state_territory = "NY" self.domain_info.state_territory = "NY"
self.domain_info.save() self.domain_info.save()
self.domain_request_2.organization_name = "super" self.domain_request.organization_name = "super"
self.domain_request.suborganization_city = "Request Suborg City" self.domain_request.suborganization_city = "Request Suborg City"
self.domain_request.suborganization_state_territory = "CA" self.domain_request.suborganization_state_territory = "CA"
self.domain_request.city = "Request City" self.domain_request.city = "Request City"