4745 implement start past report - #4783
Conversation
b2a0d34 to
1fa7e41
Compare
42646bf to
efb06c3
Compare
9814659 to
d4322d3
Compare
6d92528 to
2f92d69
Compare
80e9f4d to
e055402
Compare
| vi.mock("@bciers/components/form/FormBase", () => ({ | ||
| default: vi.fn(({ children, onChange, onSubmit }) => ( | ||
| <form | ||
| onSubmit={(event) => { | ||
| event.preventDefault(); | ||
| onSubmit({ | ||
| formData: { | ||
| reporting_year: 2023, | ||
| operation_id: "operation-1", | ||
| registration_purpose: "Reporting Operation", | ||
| }, | ||
| }); | ||
| }} | ||
| > | ||
| <button | ||
| type="button" | ||
| onClick={() => | ||
| onChange({ | ||
| formData: { | ||
| reporting_year: 2023, | ||
| operation_id: "operation-1", | ||
| registration_purpose: "Reporting Operation", | ||
| }, | ||
| }) | ||
| } | ||
| > | ||
| Mock Change | ||
| </button> | ||
|
|
||
| {children} | ||
| </form> | ||
| )), | ||
| })); |
There was a problem hiding this comment.
Do we need to mock FormBase? I think we could just let the test render without mocking.
There was a problem hiding this comment.
Nit: We have a couple of any types in this file. It would be great if we could replace them with the appropriate types.
| # the designated operator for the selected reporting year | ||
| if designated_operator_timeline.operator.id != user_operator.operator_id: | ||
| raise UserError( | ||
| f"This operation was owned by another operation in {reporting_year}, " |
There was a problem hiding this comment.
owned by another operation operator
| def _get_previous_reporting_years(cls) -> QuerySet[ReportingYear]: | ||
| """ | ||
| Returns reporting years that are eligible for the Start Past Report workflow | ||
|
|
||
| Only reporting years from MIN_REPORTING_YEAR up to (but not including) the current | ||
| reporting year are returned. | ||
| """ | ||
| current_reporting_year = ReportingYearService.get_current_reporting_year() | ||
|
|
||
| return ReportingYear.objects.filter( | ||
| reporting_year__gte=cls.MIN_REPORTING_YEAR, | ||
| reporting_year__lt=current_reporting_year.reporting_year, | ||
| ).order_by("-reporting_year") |
There was a problem hiding this comment.
Should we move this to ReportingYearService?
| def create_report_for_reporting_year( | ||
| cls, | ||
| user_guid: UUID, | ||
| data: Any, |
There was a problem hiding this comment.
A dataclass instead of Any?
| operator = operator_baker() | ||
| operation = operation_baker( |
There was a problem hiding this comment.
We have some existing operator_baker() and operation_baker() helpers from before we decided to standardize on recipes. I think it would be better to use recipes here as well.
For the existing usages, we can replace them with recipes in a separate tech debt ticket. I'll make a note to create one. 😃
| { label: "View annual report(s)", href: "/reports/current-reports" }, | ||
| { label: "View past reports", href: "/reports/previous-years" }, | ||
| { label: "Current Reporting Year", href: "/reports/current-reports" }, | ||
| { label: "Previous Reporting Years", href: "/reports/previous-years" }, | ||
| ] | ||
| : [ | ||
| //tabs for internal users | ||
| { label: "View annual reports", href: "/reports/current-reports" }, | ||
| { label: "View past reports", href: "/reports/previous-years" }, | ||
| { label: "Current Reporting Year", href: "/reports/current-reports" }, | ||
| { label: "Previous Reporting Years", href: "/reports/previous-years" }, |
There was a problem hiding this comment.
Since we're changing these labels, should we also update the ones on the dashboard to keep them in sync?
92dd9a5 to
0d68f4e
Compare
| def load_dashboard_fixtures(apps, schema_editor): | ||
| from django.core.management import call_command | ||
|
|
||
| fixture_files = [ | ||
| 'common/fixtures/dashboard/bciers/external.json', | ||
| 'common/fixtures/dashboard/bciers/internal.json', | ||
| 'common/fixtures/dashboard/operators/internal.json', | ||
| ] | ||
|
|
||
| # Delete all existing DashboardData objects | ||
| DashboardData = apps.get_model('common', 'DashboardData') | ||
| DashboardData.objects.all().delete() | ||
|
|
||
| # Load the fixtures | ||
| for fixture in fixture_files: | ||
| call_command('loaddata', fixture) |
There was a problem hiding this comment.
We already have a util for it:
cas-registration/bc_obps/common/utils.py
Line 61 in 3c62065
pbastia
left a comment
There was a problem hiding this comment.
Started going through it and just left a bunch of mostly nitpicks that don't necessarily need to be addressed. Great work so far!
| def load_dashboard_fixtures(apps, schema_editor): | ||
| from django.core.management import call_command | ||
|
|
||
| fixture_files = [ | ||
| 'common/fixtures/dashboard/bciers/external.json', | ||
| 'common/fixtures/dashboard/bciers/internal.json', | ||
| 'common/fixtures/dashboard/operators/internal.json', | ||
| ] | ||
|
|
||
| # Delete all existing DashboardData objects | ||
| DashboardData = apps.get_model('common', 'DashboardData') | ||
| DashboardData.objects.all().delete() | ||
|
|
||
| # Load the fixtures | ||
| for fixture in fixture_files: | ||
| call_command('loaddata', fixture) |
There was a problem hiding this comment.
This code already exists: reset_dashboard_data()in common/utils.py
The migration could just call that function in its RunPython method
|
|
||
| class TestOperationsPreviousReportableEndpoint(CommonTestSetup): | ||
| @patch("service.operation_service.OperationService.list_previous_reportable_operations") | ||
| def test_list_previous_reportable_operations( |
There was a problem hiding this comment.
nit: method name
| def test_list_previous_reportable_operations( | |
| def test_calls_and_returns_the_service_method_output( |
| reporting_years = ReportingYearService.get_previous_reporting_years() | ||
|
|
||
| # Assert | ||
| assert list(reporting_years.values_list("reporting_year", flat=True)) == [2024] |
There was a problem hiding this comment.
nit: we could use assertQuerySetEquals, pytest exposes them too if we don't want to extend TestCase
| empty_result = ( | ||
| OperationDesignatedOperatorTimelineService.get_operation_designated_operators_for_reporting_years( | ||
| operation_ids=set(), | ||
| reporting_years={2024, 2025}, | ||
| ) | ||
| ) | ||
| assert empty_result == {} | ||
|
|
||
| empty_result = ( | ||
| OperationDesignatedOperatorTimelineService.get_operation_designated_operators_for_reporting_years( | ||
| operation_ids={operation.id}, | ||
| reporting_years=set(), | ||
| ) | ||
| ) | ||
| assert empty_result == {} |
There was a problem hiding this comment.
nit: these could be individual test cases
| ordered=False, | ||
| ) | ||
|
|
||
| def test_create_report_for_reporting_year_uses_selected_registration_purpose(self): |
There was a problem hiding this comment.
nit: maybe we can split those tests in its own testfile, for readability. This one is getting really really long
| "Only currently registered operations can be used to create a report for this reporting year.", | ||
| ) | ||
|
|
||
| def test_create_report_for_reporting_year_rejects_existing_report(self): |
There was a problem hiding this comment.
nit: it seems like these tests are all setup the same way, they would be good candidates for parametrization
| if start_date is None: | ||
| continue |
There was a problem hiding this comment.
elements with a None start_date have been filtered out just above, we can remove those two lines
| min_year = min(reporting_years) | ||
| max_year = max(reporting_years) |
There was a problem hiding this comment.
This assumes a continuous set of reporting years, otherwise the method will behave weirdly for disjointed sets. I suggest having the user pass min_year and max_year as parameters instead.
5e6801a to
a46fc97
Compare
6ae6a30 to
308b461
Compare
pbastia
left a comment
There was a problem hiding this comment.
A few more things, but this is great! Approved once the non-nit comments are addressed.
Very nice work!
|
|
||
|
|
||
| class ReportingYearService: | ||
| MIN_REPORTING_YEAR = 2024 |
There was a problem hiding this comment.
Hardcoding this defeats the purpose of storing valid reporting years in the database (I'll make a separate PR to remove 2023 that shouldn't be there). Then we can just filter "All reporting years before the current one"
| try { | ||
| const finalReviewData = await getFinalReviewData(version_id); | ||
| setData(finalReviewData); | ||
| } catch (error) { | ||
| console.error("FinalReviewForm.fetchData() failed", error); | ||
| setError(error instanceof Error ? error : new Error(String(error))); | ||
| } finally { | ||
| setLoading(false); |
There was a problem hiding this comment.
We might want to raise an error instead to have our error boundary catch it and notify Sentry, otherwise this just disappears and relies on users emailing us about it
| <div className="flex justify-start gap-3 pt-6"> | ||
| <Button | ||
| variant="outlined" | ||
| onClick={() => router.back()} |
There was a problem hiding this comment.
This should probably navigate to the past reports page, independently of how the user got here
| { | ||
| body: JSON.stringify(payload), | ||
| }, | ||
| )) as CreateReportResponse | number; |
There was a problem hiding this comment.
The naming makes it sound like the "CreateReportResponse" is the valid, nominal case
| )) as CreateReportResponse | number; | |
| )) as CreateReportErrorResponse | number; |
| const mockActionHandler = vi.mocked(actionHandler); | ||
| const mockUseRouter = vi.mocked(useRouter); | ||
|
|
||
| const schema: RJSFSchema = { |
There was a problem hiding this comment.
using a test schema for the component has us testing RJSF internals, just verifying that it displays a test schema properly.
I suggest using the real generated schema, this way we'll catch regressions in functionality
| @classmethod | ||
| def _add_reportable_operation( | ||
| cls, | ||
| reportable_operations: list[dict], | ||
| added_operation_years: set[tuple[UUID, int]], | ||
| operation: Operation, | ||
| reporting_year: ReportingYear, | ||
| is_current_registered_fallback: bool, | ||
| ) -> None: |
There was a problem hiding this comment.
nit: coding style, particularly in class or static methods, we should try avoid functions that modify data structures in place and act as a side-effect.
Instead, the function should take inputs, treat them as immutable, and return new outputs
chore: revert
chore: cleanup chore: cleanup chore: add registration purpose to startReport schema chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup
chore: cleanup
chore: cleanup chore: cleanup
chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup
chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup
70dd94e to
97967b8
Compare
chore: cleanup chore: cleanup chore: cleanup chore: cleanup
db7b2ba to
8fe5d82
Compare

Ticket: 4745
🚀 Impact
🔬 Local Testing:
Start Test Environment
cd bc_obps make prepare_backendTest: Start a previous report
bc-cas-devExpected Results:
Current Reporting YearPrevious Years ReportingPrevious Years ReportingFile Previous Years ReportExpected Results:
StartExpected Results:
Review Operation Informationdisplays as expectedSyncbuton on Review Operation Information, Review Facilities, and Review Facility Information pageExpected Results:
Expected Results:
Test: Cannot start a previous report
Test: Start a previous report 1-8 with operationBrine LFO - Registered - No BORO and BCGHG ID - name from admin`Expected Results: