44
55from datetime import datetime
66from io import BytesIO
7+ import json
78from typing import List
89
910import pandas as pd
@@ -461,6 +462,36 @@ def _get_first_requirement_source_sub_query():
461462 )
462463
463464
465+ def _get_all_requirement_sources_sub_query ():
466+ """Get all unique requirement source names for each requirement."""
467+
468+ return (
469+ db .session .query (
470+ InspectionReqSourceDetailModel .requirement_id ,
471+ func .array_agg (
472+ func .distinct (
473+ cast (
474+ func .json_build_object (
475+ 'id' , RequirementSourceOptionModel .id ,
476+ 'name' , RequirementSourceOptionModel .name
477+ ), db .Text
478+ )
479+ )
480+ ).label ("all_sources" ),
481+ )
482+ .join (
483+ RequirementSourceOptionModel ,
484+ InspectionReqSourceDetailModel .requirement_source_id == RequirementSourceOptionModel .id ,
485+ )
486+ .filter (
487+ InspectionReqSourceDetailModel .is_active .is_ (True ),
488+ InspectionReqSourceDetailModel .is_deleted .is_ (False ),
489+ )
490+ .group_by (InspectionReqSourceDetailModel .requirement_id )
491+ .subquery ("all_requirement_sources" )
492+ )
493+
494+
464495def _get_requirement_order_sub_query ():
465496 """Get requirement order sub query."""
466497 return (
@@ -633,6 +664,7 @@ def _build_inspection_requirements_query(args, enable_pagination=True):
633664 # Get subqueries
634665 subqueries = {
635666 "first_requirement_source" : _get_first_requirement_source_sub_query (),
667+ "all_requirement_sources" : _get_all_requirement_sources_sub_query (),
636668 "requirement_order" : _get_requirement_order_sub_query (),
637669 "requirement_warning_letter" : _get_requirement_warning_letter_sub_query (),
638670 "requirement_violation_ticket" : _get_requirement_violation_ticket_sub_query (),
@@ -687,6 +719,7 @@ def _build_inspection_requirements_query(args, enable_pagination=True):
687719 models ["restorative_justice" ].restorative_justice_number .label (
688720 "restorative_justice_number"
689721 ),
722+ subqueries ["all_requirement_sources" ].c .all_sources .label ("requirement_sources" ),
690723 )
691724 .join (
692725 models ["topic" ],
@@ -834,6 +867,10 @@ def _build_inspection_requirements_query(args, enable_pagination=True):
834867 models ["restorative_justice" ].is_active .is_ (True ),
835868 ),
836869 )
870+ .outerjoin (
871+ subqueries ["all_requirement_sources" ],
872+ models ["req" ].id == subqueries ["all_requirement_sources" ].c .requirement_id ,
873+ )
837874 .filter (models ["req" ].is_active .is_ (True ), models ["req" ].is_deleted .is_ (False ))
838875 .order_by (models ["req" ].id , models ["enf_map" ].enforcement_action_id )
839876 .options (
@@ -849,7 +886,7 @@ def _build_inspection_requirements_query(args, enable_pagination=True):
849886
850887 # Apply pagination if requested
851888 if enable_pagination :
852- return _apply_pagination (base_query , args , ** models )
889+ return _apply_pagination (base_query , args , subqueries , ** models )
853890 return base_query
854891
855892
@@ -1025,12 +1062,13 @@ def _apply_filters(query, args, **kwargs): # pylint: disable=too-many-arguments
10251062 return query
10261063
10271064
1028- def _apply_pagination (query , args , ** kwargs ):
1065+ def _apply_pagination (query , args , subqueries , ** kwargs ):
10291066 """Apply pagination to the query.
10301067
10311068 Args:
10321069 query: The SQLAlchemy query to paginate
10331070 args: Query arguments containing pagination parameters
1071+ subqueries: Dictionary containing subqueries
10341072 **kwargs: Model aliases
10351073
10361074 Returns:
@@ -1128,6 +1166,8 @@ def _apply_pagination(query, args, **kwargs):
11281166 reference_models ["restorative_justice" ].restorative_justice_number .label (
11291167 "restorative_justice_number"
11301168 ),
1169+ # Include all requirement source IDs
1170+ subqueries ["all_requirement_sources" ].c .all_sources .label ("requirement_sources" ),
11311171 # Include enforcement document IDs for distinct key
11321172 reference_models ["order" ].id .label ("order_id" ),
11331173 reference_models ["warning_letter" ].id .label ("warning_letter_id" ),
@@ -1179,6 +1219,7 @@ def _apply_pagination(query, args, **kwargs):
11791219 subq .c .admin_penalty_number .label ("admin_penalty_number" ),
11801220 subq .c .charge_rec_number .label ("charge_rec_number" ),
11811221 subq .c .restorative_justice_number .label ("restorative_justice_number" ),
1222+ subq .c .requirement_sources .label ("requirement_sources" ),
11821223 subq .c .order_id .label ("order_id" ),
11831224 subq .c .warning_letter_id .label ("warning_letter_id" ),
11841225 subq .c .violation_ticket_id .label ("violation_ticket_id" ),
@@ -1465,6 +1506,9 @@ def _process_inspection_requirement_query_results(query_results):
14651506 )
14661507 item ["enforcement_number" ] = _get_enforcement_number_by_type (result )
14671508
1509+ # Add all requirement source names
1510+ item ["requirement_sources" ] = getattr (result , "requirement_sources" , None )
1511+
14681512 processed_requirements .append (item )
14691513 return processed_requirements
14701514
@@ -1514,6 +1558,12 @@ def _convert_enum_string_to_object(enum_string, enum_class_map):
15141558
15151559def _make_requirement_detail_object (requirements : list ):
15161560 """Make requirement detail object."""
1561+
1562+ def parse_requirement_sources (sources ):
1563+ if not sources :
1564+ return []
1565+ return [json .loads (item ) for item in sources ]
1566+
15171567 requirement_details = []
15181568 for requirement in requirements :
15191569 item = {
@@ -1535,6 +1585,7 @@ def _make_requirement_detail_object(requirements: list):
15351585 "name" : requirement ["inspection_status" ].value ,
15361586 },
15371587 "enforcement_number" : requirement ["enforcement_number" ],
1588+ "requirement_sources" : parse_requirement_sources (requirement .get ("requirement_sources" )),
15381589 }
15391590
15401591 # Handle status field - already converted to proper object format in
0 commit comments