Skip to content

Commit dc98188

Browse files
authored
Refactor reports to get them working with current DB structure (#1369)
1 parent 3285482 commit dc98188

File tree

4 files changed

+258
-198
lines changed

4 files changed

+258
-198
lines changed

epictrack-api/src/api/reports/anticipated_schedule_report.py

Lines changed: 181 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,31 @@
11
"""Classes for specific report types."""
2+
from datetime import timedelta
3+
24
from flask import jsonify
5+
from sqlalchemy import and_, func, or_
6+
from sqlalchemy.dialects.postgresql import INTERVAL
7+
from sqlalchemy.orm import aliased
8+
9+
from api.models import db
10+
from api.models.ea_act import EAAct
11+
from api.models.event import Event
12+
from api.models.event_category import EventCategory
13+
from api.models.event_configuration import EventConfiguration
14+
from api.models.ministry import Ministry
15+
from api.models.phase_code import PhaseCode
16+
from api.models.project import Project
17+
from api.models.proponent import Proponent
18+
from api.models.region import Region
19+
from api.models.staff import Staff
20+
from api.models.substitution_acts import SubstitutionAct
21+
from api.models.work import Work
22+
from api.models.work_phase import WorkPhase
23+
from api.models.work_status import WorkStatus
324

425
from .cdog_client import CDOGClient
526
from .report_factory import ReportFactory
627

28+
729
# pylint:disable=not-callable
830

931

@@ -40,156 +62,165 @@ def __init__(self, filters):
4062

4163
def _fetch_data(self, report_date):
4264
"""Fetches the relevant data for EA Anticipated Schedule Report"""
43-
# start_date = report_date + timedelta(days=-7)
44-
# eac_decision_by = aliased(Staff)
45-
# decision_by = aliased(Staff)
46-
# pecp_event = aliased(Event)
47-
48-
pecps = {} # Milestone.query.filter(Milestone.milestone_type_id == 11).all()
49-
pecps = [x.id for x in pecps]
50-
51-
decision_miletones = {}
52-
# Milestone.query.filter(
53-
# Milestone.milestone_type_id.in_((1, 4))
54-
# ).all()
55-
decision_miletones = [x.id for x in decision_miletones]
56-
57-
# next_decision_event_query = (
58-
# db.session.query(
59-
# Event.work_id,
60-
# func.min(Event.anticipated_start_date).label(
61-
# "min_anticipated_start_date"
62-
# ),
63-
# )
64-
# .filter(
65-
# Event.anticipated_start_date >= start_date,
66-
# Event.milestone_id.in_(decision_miletones),
67-
# )
68-
# .group_by(Event.work_id)
69-
# .subquery()
70-
# )
71-
72-
# next_pecp_query = (
73-
# db.session.query(
74-
# Engagement.work_id,
75-
# func.min(Engagement.start_date).label("min_start_date"),
76-
# )
77-
# .join(WorkEngagement)
78-
# .filter(
79-
# Engagement.start_date >= start_date,
80-
# WorkEngagement.milestone_id.in_(pecps),
81-
# )
82-
# .group_by(Engagement.work_id)
83-
# .subquery()
84-
# )
85-
86-
# status_update_max_date_query = (
87-
# db.session.query(
88-
# WorkStatus.work_id,
89-
# func.max(WorkStatus.posted_date).label("max_posted_date"),
90-
# )
91-
# .group_by(WorkStatus.work_id)
92-
# .subquery()
93-
# )
94-
95-
# latest_status_updates = WorkStatus.query.filter(
96-
# WorkStatus.posted_date >= start_date
97-
# ).join(
98-
# status_update_max_date_query,
99-
# and_(
100-
# WorkStatus.work_id == status_update_max_date_query.c.work_id,
101-
# WorkStatus.posted_date ==
102-
# status_update_max_date_query.c.max_posted_date,
103-
# ),
104-
# )
105-
106-
# results_qry = (
107-
# latest_status_updates.join(Work)
108-
# .join(Event)
109-
# .join(
110-
# next_decision_event_query,
111-
# and_(
112-
# Event.work_id == next_decision_event_query.c.work_id,
113-
# Event.anticipated_start_date ==
114-
# next_decision_event_query.c.min_anticipated_start_date,
115-
# ),
116-
# )
117-
# .join(
118-
# Milestone,
119-
# and_(
120-
# Milestone.id == Event.milestone_id,
121-
# Milestone.id.in_(decision_miletones),
122-
# ),
123-
# )
124-
# .join(PhaseCode, Milestone.phase_id == PhaseCode.id)
125-
# .join(Project, Work.project_id == Project.id)
126-
# .join(Proponent)
127-
# .join(Region, Region.id == Project.region_id_env)
128-
# .join(EAAct, EAAct.id == Work.ea_act_id)
129-
# .join(Ministry)
130-
# .outerjoin(eac_decision_by, Work.eac_decision_by)
131-
# .outerjoin(decision_by, Work.decision_by)
132-
# .outerjoin(SubstitutionAct)
133-
# .outerjoin(
134-
# WorkEngagement,
135-
# and_(
136-
# WorkEngagement.project_id == Work.project_id,
137-
# WorkEngagement.milestone_id.in_(pecps),
138-
# ),
139-
# )
140-
# .outerjoin(Engagement, WorkEngagement.engagement)
141-
# .outerjoin(
142-
# next_pecp_query,
143-
# and_(
144-
# next_pecp_query.c.work_id == Work.id,
145-
# WorkEngagement.project_id == Work.project_id,
146-
# ),
147-
# )
148-
# # FILTER ENTRIES MATCHING MIN DATE FOR NEXT PECP OR NO WORK ENGAGEMENTS (FOR AMENDMENTS)
149-
# .filter(
150-
# or_(
151-
# next_pecp_query.c.min_start_date == Engagement.start_date,
152-
# WorkEngagement.id.is_(None),
153-
# )
154-
# )
155-
# .outerjoin(
156-
# pecp_event,
157-
# and_(
158-
# next_pecp_query.c.work_id == pecp_event.work_id,
159-
# next_pecp_query.c.min_start_date == pecp_event.start_date,
160-
# pecp_event.milestone_id.in_(pecps),
161-
# ),
162-
# )
163-
# .add_columns(
164-
# PhaseCode.name.label("phase_name"),
165-
# WorkStatus.posted_date.label("date_updated"),
166-
# Project.name.label("project_name"),
167-
# Proponent.name.label("proponent"),
168-
# Region.name.label("region"),
169-
# Project.address.label("location"),
170-
# EAAct.name.label("ea_act"),
171-
# SubstitutionAct.name.label("substitution_act"),
172-
# Project.description.label("project_description"),
173-
# Event.anticipated_end_date.label("anticipated_decision_date"),
174-
# WorkStatus.status_text.label("additional_info"),
175-
# Ministry.name.label("ministry_name"),
176-
# Event.anticipated_end_date.label("referral_date"),
177-
# eac_decision_by.full_name.label("eac_decision_by"),
178-
# decision_by.full_name.label("decision_by"),
179-
# Milestone.milestone_type_id.label("milestone_type"),
180-
# func.coalesce(pecp_event.title, Engagement.title).label(
181-
# "next_pecp_title"
182-
# ),
183-
# func.coalesce(
184-
# pecp_event.start_date,
185-
# pecp_event.anticipated_start_date,
186-
# Engagement.start_date,
187-
# ).label("next_pecp_date"),
188-
# pecp_event.short_description.label("next_pecp_short_description"),
189-
# )
190-
# )
191-
# return results_qry.all()
192-
return {}
65+
start_date = report_date + timedelta(days=-7)
66+
eac_decision_by = aliased(Staff)
67+
decision_by = aliased(Staff)
68+
pecp_event = aliased(Event)
69+
70+
pecp_category = EventCategory.query.filter(EventCategory.name == "PCP").first()
71+
pecp_configuration_ids = EventConfiguration.query.filter(
72+
EventConfiguration.event_category_id == pecp_category.id
73+
).all()
74+
pecp_configuration_ids = [x.id for x in pecp_configuration_ids]
75+
76+
decision_category = EventCategory.query.filter(
77+
EventCategory.name == "Decision"
78+
).first()
79+
decision_configuration_ids = EventConfiguration.query.filter(
80+
EventConfiguration.event_category_id == decision_category.id
81+
).all()
82+
decision_configuration_ids = [x.id for x in decision_configuration_ids]
83+
84+
next_decision_event_query = (
85+
db.session.query(
86+
Event.work_id,
87+
func.min(Event.anticipated_date).label("min_anticipated_date"),
88+
)
89+
.filter(
90+
Event.anticipated_date >= start_date,
91+
Event.event_configuration_id.in_(decision_configuration_ids),
92+
)
93+
.group_by(Event.work_id)
94+
.subquery()
95+
)
96+
97+
next_pecp_query = (
98+
db.session.query(
99+
Event.work_id,
100+
func.min(Event.actual_date).label("min_start_date"),
101+
)
102+
.filter(
103+
Event.actual_date >= start_date,
104+
Event.event_configuration_id.in_(pecp_configuration_ids),
105+
)
106+
.group_by(Event.work_id)
107+
.subquery()
108+
)
109+
110+
status_update_max_date_query = (
111+
db.session.query(
112+
WorkStatus.work_id,
113+
func.max(WorkStatus.posted_date).label("max_posted_date"),
114+
)
115+
.group_by(WorkStatus.work_id)
116+
.subquery()
117+
)
118+
119+
latest_status_updates = WorkStatus.query.filter(
120+
WorkStatus.posted_date >= start_date
121+
).join(
122+
status_update_max_date_query,
123+
and_(
124+
WorkStatus.work_id == status_update_max_date_query.c.work_id,
125+
WorkStatus.posted_date
126+
== status_update_max_date_query.c.max_posted_date,
127+
),
128+
)
129+
130+
results_qry = (
131+
latest_status_updates.join(Work)
132+
.join(Event)
133+
.join(
134+
next_decision_event_query,
135+
and_(
136+
Event.work_id == next_decision_event_query.c.work_id,
137+
Event.anticipated_date
138+
== next_decision_event_query.c.min_anticipated_date,
139+
),
140+
)
141+
.join(
142+
EventConfiguration,
143+
and_(
144+
EventConfiguration.id == Event.event_configuration_id,
145+
EventConfiguration.id.in_(decision_configuration_ids),
146+
),
147+
)
148+
.join(WorkPhase, EventConfiguration.work_phase_id == WorkPhase.id)
149+
.join(PhaseCode, WorkPhase.phase_id == PhaseCode.id)
150+
.join(Project, Work.project_id == Project.id)
151+
.join(Proponent)
152+
.join(Region, Region.id == Project.region_id_env)
153+
.join(EAAct, EAAct.id == Work.ea_act_id)
154+
.join(Ministry)
155+
.outerjoin(eac_decision_by, Work.eac_decision_by)
156+
.outerjoin(decision_by, Work.decision_by)
157+
.outerjoin(SubstitutionAct)
158+
# .outerjoin(
159+
# WorkEngagement,
160+
# and_(
161+
# WorkEngagement.project_id == Work.project_id,
162+
# WorkEngagement.milestone_id.in_(pecp_configuration_ids),
163+
# ),
164+
# )
165+
# .outerjoin(Engagement, WorkEngagement.engagement)
166+
.outerjoin(
167+
pecp_event,
168+
and_(
169+
pecp_event.work_id == Work.id,
170+
# next_pecp_query.c.min_start_date == pecp_event.actual_date,
171+
pecp_event.event_configuration_id.in_(pecp_configuration_ids),
172+
),
173+
)
174+
.outerjoin(
175+
next_pecp_query,
176+
and_(
177+
next_pecp_query.c.work_id == pecp_event.work_id,
178+
next_pecp_query.c.min_start_date == pecp_event.actual_date,
179+
Work.project_id == Work.project_id,
180+
),
181+
)
182+
# FILTER ENTRIES MATCHING MIN DATE FOR NEXT PECP OR NO WORK ENGAGEMENTS (FOR AMENDMENTS)
183+
.filter(
184+
or_(
185+
next_pecp_query.c.min_start_date == pecp_event.actual_date,
186+
pecp_event.id.is_(None),
187+
)
188+
)
189+
.add_columns(
190+
PhaseCode.name.label("phase_name"),
191+
WorkStatus.posted_date.label("date_updated"),
192+
Project.name.label("project_name"),
193+
Proponent.name.label("proponent"),
194+
Region.name.label("region"),
195+
Project.address.label("location"),
196+
EAAct.name.label("ea_act"),
197+
SubstitutionAct.name.label("substitution_act"),
198+
Project.description.label("project_description"),
199+
(
200+
Event.anticipated_date + func.cast(func.concat(Event.number_of_days, " DAYS"),
201+
INTERVAL)
202+
).label("anticipated_decision_date"),
203+
# Event.anticipated_end_date.label("anticipated_decision_date"),
204+
WorkStatus.description.label("additional_info"),
205+
Ministry.name.label("ministry_name"),
206+
(
207+
Event.anticipated_date + func.cast(func.concat(Event.number_of_days, " DAYS"),
208+
INTERVAL)
209+
).label("referral_date"),
210+
# Event.anticipated_end_date.label("referral_date"),
211+
eac_decision_by.full_name.label("eac_decision_by"),
212+
decision_by.full_name.label("decision_by"),
213+
EventConfiguration.event_type_id.label("milestone_type"),
214+
func.coalesce(pecp_event.name, Event.name).label("next_pecp_title"),
215+
func.coalesce(
216+
pecp_event.actual_date,
217+
pecp_event.anticipated_date,
218+
Event.actual_date,
219+
).label("next_pecp_date"),
220+
pecp_event.notes.label("next_pecp_short_description"),
221+
)
222+
)
223+
return results_qry.all()
193224

194225
def generate_report(self, report_date, return_type):
195226
"""Generates a report and returns it"""

epictrack-api/src/api/reports/resource_forecast_report.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ def _fetch_data(self, report_date: datetime): # pylint: disable=too-many-locals
355355
Event.query.filter(
356356
Event.work_id.in_(work_ids),
357357
Event.event_configuration_id.in_(self.start_event_configurations),
358-
func.coalesce(Event.actual_date, Event.anticipated_date) >= first_month,
358+
func.coalesce(Event.actual_date, Event.anticipated_date) <= self.end_date,
359359
)
360360
.join(
361361
EventConfiguration,

0 commit comments

Comments
 (0)