From 424cdd0466d970548e093046fd849623e5d13f67 Mon Sep 17 00:00:00 2001 From: ayeshmcg Date: Thu, 31 Oct 2024 15:36:57 -0700 Subject: [PATCH 1/6] feat:added new entrant info page --- .../new-entrant-information/page.tsx | 14 ++ .../new-entrant-information/page.tsx | 14 ++ .../NewEntrantInformation.tsx | 15 ++ .../NewEntrantInformationForm.tsx | 84 ++++++++ .../additionalMessage.tsx | 15 ++ .../newEntrantInformation.ts | 192 ++++++++++++++++++ 6 files changed, 334 insertions(+) create mode 100644 bciers/apps/reporting/src/app/bceidbusiness/industry_user/new-entrant-information/page.tsx create mode 100644 bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/new-entrant-information/page.tsx create mode 100644 bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx create mode 100644 bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx create mode 100644 bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx create mode 100644 bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts diff --git a/bciers/apps/reporting/src/app/bceidbusiness/industry_user/new-entrant-information/page.tsx b/bciers/apps/reporting/src/app/bceidbusiness/industry_user/new-entrant-information/page.tsx new file mode 100644 index 0000000000..8da3acec77 --- /dev/null +++ b/bciers/apps/reporting/src/app/bceidbusiness/industry_user/new-entrant-information/page.tsx @@ -0,0 +1,14 @@ +import { Suspense } from "react"; +import Loading from "@bciers/components/loading/SkeletonForm"; +import NewEntrantInformation from "@reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation"; +interface PageProps { + params: { version_id: number }; +} + +export default async function Page({ params }: PageProps) { + return ( + }> + + + ); +} diff --git a/bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/new-entrant-information/page.tsx b/bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/new-entrant-information/page.tsx new file mode 100644 index 0000000000..8da3acec77 --- /dev/null +++ b/bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/new-entrant-information/page.tsx @@ -0,0 +1,14 @@ +import { Suspense } from "react"; +import Loading from "@bciers/components/loading/SkeletonForm"; +import NewEntrantInformation from "@reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation"; +interface PageProps { + params: { version_id: number }; +} + +export default async function Page({ params }: PageProps) { + return ( + }> + + + ); +} diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx new file mode 100644 index 0000000000..30fe09076d --- /dev/null +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx @@ -0,0 +1,15 @@ +import { Suspense } from "react"; +import Loading from "@bciers/components/loading/SkeletonForm"; +import NewEntrantInformationForm from "@reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm"; + +export default async function NewEntrantInformation({ + versionId, +}: { + versionId: number; +}) { + return ( + }> + + + ); +} diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx new file mode 100644 index 0000000000..ea4d9ca0b0 --- /dev/null +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx @@ -0,0 +1,84 @@ +"use client"; + +import React, { useState } from "react"; +import MultiStepFormWithTaskList from "@bciers/components/form/MultiStepFormWithTaskList"; +import { TaskListElement } from "@bciers/components/navigation/reportingTaskList/types"; +import { useRouter } from "next/navigation"; + +import { actionHandler } from "@bciers/actions"; +import { + newEntrantInformationSchema, + newEntrantInformationUiSchema, +} from "@reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation"; + +const baseUrl = "/reports"; +const cancelUrl = "/reports"; + +interface AdditionalReportingDataProps { + versionId: number; +} + +export default function NewEntrantInformationForm({ + versionId, +}: AdditionalReportingDataProps) { + const [formData, setFormData] = useState(); + + const router = useRouter(); + const saveAndContinueUrl = `/reports/${versionId}/new-entrant-information`; + + const taskListElements: TaskListElement[] = [ + { + type: "Page", + title: "Additional reporting data", + isChecked: true, + link: `/reports/${versionId}/additional-reporting-data`, + }, + { + type: "Page", + title: "New entrant information", + isActive: true, + link: `/reports/${versionId}/new-entrant-information`, + }, + ]; + + const handleSubmit = async (data: any) => { + const endpoint = `reporting/report-version/${versionId}/additional-data`; + const method = "POST"; + + const payload = { + report_version: versionId, + ...data.captured_emissions_section, + ...data.additional_data_section, + }; + + const response = await actionHandler(endpoint, method, endpoint, { + body: JSON.stringify(payload), + }); + if (response) { + router.push(saveAndContinueUrl); + } + }; + + return ( + { + setFormData(data.formData); + }} + onSubmit={(data: any) => handleSubmit(data.formData)} + /> + ); +} diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx new file mode 100644 index 0000000000..a52c382dd8 --- /dev/null +++ b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx @@ -0,0 +1,15 @@ +import { Typography } from "@mui/material"; +import { BC_GOV_BACKGROUND_COLOR_BLUE } from "@bciers/styles"; +export const newEntrantInfo = ( + <> + + This section applies to operations that fall under{" "} + new entrant category. + + +); diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts new file mode 100644 index 0000000000..fb87a0e5a1 --- /dev/null +++ b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts @@ -0,0 +1,192 @@ +import { RJSFSchema } from "@rjsf/utils"; +import FieldTemplate from "@bciers/components/form/fields/FieldTemplate"; +import { + InlineFieldTemplate, + TitleOnlyFieldTemplate, +} from "@bciers/components/form/fields"; +import SectionFieldTemplate from "@bciers/components/form/fields/SectionFieldTemplate"; +import { DateWidget } from "@bciers/components/form/widgets"; +import { newEntrantInfo } from "@reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage"; + +export const newEntrantInformationSchema: RJSFSchema = { + type: "object", + title: "Additional Reporting Data", + properties: { + purpose_note: { type: "object", readOnly: true }, + date_of_authorization: { + type: "string", + title: "Date of authorization", + }, + date_of_first_shipment: { + type: "string", + title: "Date of first shipment", + }, + date_of_new_entrant_period_began: { + type: "string", + title: "Date new entrant period began", + }, + assertion_statement: { + type: "boolean", + title: "Assertion statement", + default: false, + }, + + emission_after_new_entrant: { + type: "object", + title: "Emission categories after new entrant period began", + properties: { + flaring_emissions: { + type: "number", + title: "Flaring emissions", + }, + fugitive_emissions: { + type: "number", + title: "Fugitive emissions", + }, + industrial_process_emissions: { + type: "number", + title: "Industrial process emissions", + }, + on_site_transportation_emissions: { + type: "number", + title: "On-site transportation emissions", + }, + stationary_fuel_combustion_emissions: { + type: "number", + title: "Stationary fuel combustion emissions", + }, + venting_emissions_useful: { + type: "number", + title: "Venting emissions - useful", + }, + venting_emissions_non_useful: { + type: "number", + title: "Venting emissions - non-useful", + }, + emissions_from_waste: { + type: "number", + title: "Emissions from waste", + }, + emissions_from_wastewater: { + type: "number", + title: "Emissions from wastewater", + }, + }, + }, + emission_excluded_by_fuel_type: { + type: "object", + title: "Emissions excluded by fuel type", + properties: { + co2_emissions_from_excluded_woody_biomass: { + type: "number", + title: "CO2 emissions from excluded woody biomass", + }, + other_emissions_from_excluded_biomasss: { + type: "number", + title: "Other emissions from excluded biomass", + }, + emissions_from_excluded_non_biomass: { + type: "number", + title: "Emissions from excluded non-biomass", + }, + }, + }, + other_excluded_emissions: { + type: "object", + title: "Other excluded emissions", + properties: { + emissions_from_line_tracing: { + type: "number", + title: + "Emissions from line tracing and non-processing and non-compression activities", + }, + emissions_from_fat_oil: { + type: "number", + title: + "Emissions from fat, oil and grease collection, refining and storage ", + }, + }, + }, + }, +}; + +export const newEntrantInformationUiSchema = { + "ui:FieldTemplate": FieldTemplate, + "ui:classNames": "form-heading-label", + "ui:options": { label: false }, + "ui:order": [ + "purpose_note", + "date_of_authorization", + "date_of_first_shipment", + "date_of_new_entrant_period_began", + "assertion_statement", + "emission_after_new_entrant", + "emission_excluded_by_fuel_type", + "other_excluded_emissions", + ], + purpose_note: { + "ui:FieldTemplate": TitleOnlyFieldTemplate, + "ui:title": newEntrantInfo, + }, + date_of_authorization: { + "ui:widget": DateWidget, + }, + + date_of_first_shipment: { + "ui:widget": DateWidget, + }, + date_of_new_entrant_period_began: { + "ui:widget": DateWidget, + }, + emission_after_new_entrant: { + "ui:FieldTemplate": SectionFieldTemplate, + flaring_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + fugitive_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + industrial_process_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + on_site_transportation_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + stationary_fuel_combustion_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + venting_emissions_useful: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + venting_emissions_non_useful: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_waste: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_wastewater: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }, + emission_excluded_by_fuel_type: { + "ui:FieldTemplate": SectionFieldTemplate, + co2_emissions_from_excluded_woody_biomass: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + other_emissions_from_excluded_biomasss: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_excluded_non_biomass: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }, + other_excluded_emissions: { + "ui:FieldTemplate": SectionFieldTemplate, + emissions_from_line_tracing: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_fat_oil: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }, +}; From 263910914de4b1dbac58a0232fc76fc22afeb540 Mon Sep 17 00:00:00 2001 From: ayeshmcg Date: Mon, 4 Nov 2024 09:47:42 -0800 Subject: [PATCH 2/6] chore:fixed import --- .../newEntrantInformation/newEntrantInformation.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts index fb87a0e5a1..60dc7e01bd 100644 --- a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts +++ b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts @@ -7,6 +7,7 @@ import { import SectionFieldTemplate from "@bciers/components/form/fields/SectionFieldTemplate"; import { DateWidget } from "@bciers/components/form/widgets"; import { newEntrantInfo } from "@reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage"; +import checkboxWidget from "@bciers/components/form/widgets/CheckboxWidget"; export const newEntrantInformationSchema: RJSFSchema = { type: "object", @@ -27,7 +28,8 @@ export const newEntrantInformationSchema: RJSFSchema = { }, assertion_statement: { type: "boolean", - title: "Assertion statement", + title: + "I certify that this operation was a reporting operation on the date that the application for designation as a new entrant was submitted to the Director under GGIRCA.", default: false, }, @@ -128,6 +130,9 @@ export const newEntrantInformationUiSchema = { "ui:FieldTemplate": TitleOnlyFieldTemplate, "ui:title": newEntrantInfo, }, + assertion_statement: { + "ui:widget": checkboxWidget, + }, date_of_authorization: { "ui:widget": DateWidget, }, From 2e0b2707d7b450f0e13bcde14f013159d7d96d62 Mon Sep 17 00:00:00 2001 From: ayeshmcg Date: Tue, 5 Nov 2024 10:37:30 -0800 Subject: [PATCH 3/6] chore:fixed schema --- bc_obps/reporting/api/__init__.py | 1 + bc_obps/reporting/api/reports.py | 22 +- ...rtnewentrant_reportnewentrantproduction.py | 237 ++++++++++++++++++ bc_obps/reporting/models/__init__.py | 4 + .../reporting/models/report_new_entrant.py | 78 ++++++ .../models/report_new_entrant_production.py | 30 +++ .../schema/report_regulated_products.py | 6 + bc_obps/service/report_service.py | 13 + .../NewEntrantInformation.tsx | 8 +- .../NewEntrantInformationForm.tsx | 2 + .../src/app/utils/getReportProducts.ts | 12 + .../additionalMessage.tsx | 9 + .../newEntrantInformation.ts | 6 +- 13 files changed, 422 insertions(+), 6 deletions(-) create mode 100644 bc_obps/reporting/migrations/0027_reportnewentrant_reportnewentrantproduction.py create mode 100644 bc_obps/reporting/models/report_new_entrant.py create mode 100644 bc_obps/reporting/models/report_new_entrant_production.py create mode 100644 bc_obps/reporting/schema/report_regulated_products.py create mode 100644 bciers/apps/reporting/src/app/utils/getReportProducts.ts diff --git a/bc_obps/reporting/api/__init__.py b/bc_obps/reporting/api/__init__.py index c7bb2e989b..63108a2275 100644 --- a/bc_obps/reporting/api/__init__.py +++ b/bc_obps/reporting/api/__init__.py @@ -10,6 +10,7 @@ from .report_person_responsible import get_report_person_responsible_by_version_id from .report_person_responsible import save_report_contact from .report_additional_data import get_registration_purpose_by_version_id +from .reports import get_regulated_products_by_version_id from .gas_type import get_gas_type from .emission_category import get_emission_category from .production_data import save_production_data diff --git a/bc_obps/reporting/api/reports.py b/bc_obps/reporting/api/reports.py index 89867db638..bf2132cddf 100644 --- a/bc_obps/reporting/api/reports.py +++ b/bc_obps/reporting/api/reports.py @@ -1,4 +1,4 @@ -from typing import Literal, Tuple +from typing import Literal, Tuple, List from common.permissions import authorize from django.http import HttpRequest @@ -13,6 +13,7 @@ from reporting.schema.reporting_year import ReportingYearOut from .router import router from ..models import ReportingYear +from ..schema.report_regulated_products import RegulatedProductOut @router.post( @@ -39,7 +40,7 @@ def start_report(request: HttpRequest, payload: StartReportIn) -> Tuple[Literal[ ) @handle_http_errors() def get_report_operation_by_version_id( - request: HttpRequest, version_id: int + request: HttpRequest, version_id: int ) -> Tuple[Literal[200], ReportOperationOut]: report_operation = ReportService.get_report_operation_by_version_id(version_id) return 200, report_operation # type: ignore @@ -55,7 +56,7 @@ def get_report_operation_by_version_id( ) @handle_http_errors() def save_report( - request: HttpRequest, version_id: int, payload: ReportOperationIn + request: HttpRequest, version_id: int, payload: ReportOperationIn ) -> Tuple[Literal[201], ReportOperationOut]: report_operation = ReportService.save_report_operation(version_id, payload) return 201, report_operation # type: ignore @@ -71,3 +72,18 @@ def save_report( @handle_http_errors() def get_reporting_year(request: HttpRequest) -> Tuple[Literal[200], ReportingYear]: return 200, ReportingYearService.get_current_reporting_year() + + +@router.get( + "/report-version/{version_id}/regulated-products", + response={200: List[RegulatedProductOut], custom_codes_4xx: Message}, + tags=EMISSIONS_REPORT_TAGS, + description="""Retrieves all regulated products associated with a report operation identified by its version ID.""", + # auth=authorize("approved_authorized_roles"), +) +@handle_http_errors() +def get_regulated_products_by_version_id( + request: HttpRequest, version_id: int +) -> Tuple[Literal[200], List[RegulatedProductOut]]: + regulated_products = ReportService.get_regulated_products_by_version_id(version_id) + return 200, regulated_products diff --git a/bc_obps/reporting/migrations/0027_reportnewentrant_reportnewentrantproduction.py b/bc_obps/reporting/migrations/0027_reportnewentrant_reportnewentrantproduction.py new file mode 100644 index 0000000000..3bafd7c3d3 --- /dev/null +++ b/bc_obps/reporting/migrations/0027_reportnewentrant_reportnewentrantproduction.py @@ -0,0 +1,237 @@ +# Generated by Django 5.0.9 on 2024-11-05 06:02 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('registration', '0048_bcobpsregulatedoperation_issued_by_and_more'), + ('reporting', '0026_reportmethodology_methodology'), + ] + + operations = [ + migrations.CreateModel( + name='ReportNewEntrant', + fields=[ + ('created_at', models.DateTimeField(auto_now_add=True, null=True)), + ('updated_at', models.DateTimeField(blank=True, null=True)), + ('archived_at', models.DateTimeField(blank=True, null=True)), + ( + 'report_version', + models.OneToOneField( + db_comment='The associated report version for this new entrant record', + on_delete=django.db.models.deletion.PROTECT, + primary_key=True, + related_name='report_new_entrant', + serialize=False, + to='reporting.reportversion', + ), + ), + ('authorization_date', models.DateTimeField(db_comment='Date of authorization for emission reporting')), + ( + 'first_shipment_date', + models.DateTimeField( + blank=True, + db_comment='Date of the first shipment related to this report (if applicable)', + null=True, + ), + ), + ( + 'new_entrant_period_start', + models.DateTimeField( + blank=True, db_comment='Start date of the new entrant reporting period', null=True + ), + ), + ( + 'assertion_statement_certified', + models.BooleanField( + blank=True, db_comment='Indicates if the assertion statement is certified', null=True + ), + ), + ( + 'flaring_emissions', + models.IntegerField( + blank=True, db_comment='Emissions from flaring activities', default=0, null=True + ), + ), + ( + 'fugitive_emissions', + models.IntegerField( + blank=True, db_comment='Unintentional emissions (fugitive)', default=0, null=True + ), + ), + ( + 'industrial_process_emissions', + models.IntegerField( + blank=True, db_comment='Emissions from industrial processes', default=0, null=True + ), + ), + ( + 'on_site_transportation_emissions', + models.IntegerField( + blank=True, db_comment='Emissions from on-site transportation', default=0, null=True + ), + ), + ( + 'stationary_fuel_combustion_emissions', + models.IntegerField( + blank=True, db_comment='Emissions from stationary fuel combustion', default=0, null=True + ), + ), + ( + 'venting_emissions_useful', + models.IntegerField(blank=True, db_comment='Venting emissions deemed useful', default=0, null=True), + ), + ( + 'venting_emissions_non_useful', + models.IntegerField(blank=True, db_comment='Non-useful venting emissions', default=0, null=True), + ), + ( + 'emissions_from_waste', + models.IntegerField(blank=True, db_comment='Emissions from waste disposal', default=0, null=True), + ), + ( + 'emissions_from_wastewater', + models.IntegerField( + blank=True, db_comment='Emissions from wastewater processing', default=0, null=True + ), + ), + ( + 'co2_emissions_from_excluded_woody_biomass', + models.IntegerField( + blank=True, db_comment='CO2 emissions from excluded woody biomass', default=0, null=True + ), + ), + ( + 'other_emissions_from_excluded_biomass', + models.IntegerField( + blank=True, db_comment='Emissions from other excluded biomass', default=0, null=True + ), + ), + ( + 'emissions_from_excluded_non_biomass', + models.IntegerField( + blank=True, db_comment='Emissions from excluded non-biomass sources', default=0, null=True + ), + ), + ( + 'emissions_from_line_tracing', + models.IntegerField( + blank=True, db_comment='Emissions from line tracing activities', default=0, null=True + ), + ), + ( + 'emissions_from_fat_oil', + models.IntegerField( + blank=True, db_comment='Emissions from fat or oil sources', default=0, null=True + ), + ), + ( + 'archived_by', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='%(class)s_archived', + to='registration.user', + ), + ), + ( + 'created_by', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='%(class)s_created', + to='registration.user', + ), + ), + ( + 'updated_by', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='%(class)s_updated', + to='registration.user', + ), + ), + ], + options={ + 'db_table': 'erc"."report_new_entrant', + 'db_table_comment': 'Table storing new entrant emissions data for the reporting system', + }, + ), + migrations.CreateModel( + name='ReportNewEntrantProduction', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, null=True)), + ('updated_at', models.DateTimeField(blank=True, null=True)), + ('archived_at', models.DateTimeField(blank=True, null=True)), + ( + 'production_amount', + models.IntegerField( + blank=True, + db_comment='The amount of production associated with this report', + default=0, + null=True, + ), + ), + ( + 'archived_by', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='%(class)s_archived', + to='registration.user', + ), + ), + ( + 'created_by', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='%(class)s_created', + to='registration.user', + ), + ), + ( + 'product', + models.ForeignKey( + db_comment='The regulated product associated with this production record', + on_delete=django.db.models.deletion.CASCADE, + related_name='new_entrant_productions', + to='registration.regulatedproduct', + ), + ), + ( + 'report_new_entrant', + models.ForeignKey( + db_comment='The new entrant report to which this production record belongs', + on_delete=django.db.models.deletion.CASCADE, + related_name='productions', + to='reporting.reportnewentrant', + ), + ), + ( + 'updated_by', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='%(class)s_updated', + to='registration.user', + ), + ), + ], + options={ + 'db_table': 'erc"."report_new_entrant_production', + 'db_table_comment': 'Table for storing production data related to new entrant emissions reporting', + }, + ), + ] diff --git a/bc_obps/reporting/models/__init__.py b/bc_obps/reporting/models/__init__.py index ec3e63ef1b..3ea6c22c44 100644 --- a/bc_obps/reporting/models/__init__.py +++ b/bc_obps/reporting/models/__init__.py @@ -28,6 +28,8 @@ from .report_additional_data import ReportAdditionalData from .emission_category import EmissionCategory from .emission_category_mapping import EmissionCategoryMapping +from .report_new_entrant import ReportNewEntrant +from .report_new_entrant_production import ReportNewEntrantProduction from .report_non_attributable_emissions import ReportNonAttributableEmissions from .report_product import ReportProduct @@ -61,4 +63,6 @@ "EmissionCategoryMapping", "ReportNonAttributableEmissions", "ReportRawActivityData", + "ReportNewEntrant", + "ReportNewEntrantProduction" ] diff --git a/bc_obps/reporting/models/report_new_entrant.py b/bc_obps/reporting/models/report_new_entrant.py new file mode 100644 index 0000000000..e5cdbfcb22 --- /dev/null +++ b/bc_obps/reporting/models/report_new_entrant.py @@ -0,0 +1,78 @@ +from django.db import models +from registration.models.time_stamped_model import TimeStampedModel +from reporting.models.report_version import ReportVersion + + +class ReportNewEntrant(TimeStampedModel): + report_version = models.OneToOneField( + ReportVersion, + on_delete=models.PROTECT, + related_name="report_new_entrant", + db_comment="The associated report version for this new entrant record", + primary_key=True, + ) + authorization_date = models.DateTimeField( + db_comment="Date of authorization for emission reporting", + ) + first_shipment_date = models.DateTimeField( + blank=True, + null=True, + db_comment="Date of the first shipment related to this report (if applicable)", + ) + new_entrant_period_start = models.DateTimeField( + blank=True, + null=True, + db_comment="Start date of the new entrant reporting period", + ) + assertion_statement_certified = models.BooleanField( + blank=True, + null=True, + db_comment="Indicates if the assertion statement is certified", + ) + flaring_emissions = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from flaring activities" + ) + fugitive_emissions = models.IntegerField( + blank=True, null=True, default=0, db_comment="Unintentional emissions (fugitive)" + ) + industrial_process_emissions = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from industrial processes" + ) + on_site_transportation_emissions = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from on-site transportation" + ) + stationary_fuel_combustion_emissions = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from stationary fuel combustion" + ) + venting_emissions_useful = models.IntegerField( + blank=True, null=True, default=0, db_comment="Venting emissions deemed useful" + ) + venting_emissions_non_useful = models.IntegerField( + blank=True, null=True, default=0, db_comment="Non-useful venting emissions" + ) + emissions_from_waste = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from waste disposal" + ) + emissions_from_wastewater = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from wastewater processing" + ) + co2_emissions_from_excluded_woody_biomass = models.IntegerField( + blank=True, null=True, default=0, db_comment="CO2 emissions from excluded woody biomass" + ) + other_emissions_from_excluded_biomass = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from other excluded biomass" + ) + emissions_from_excluded_non_biomass = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from excluded non-biomass sources" + ) + emissions_from_line_tracing = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from line tracing activities" + ) + emissions_from_fat_oil = models.IntegerField( + blank=True, null=True, default=0, db_comment="Emissions from fat or oil sources" + ) + + class Meta: + db_table = 'erc"."report_new_entrant' + app_label = 'reporting' + db_table_comment = "Table storing new entrant emissions data for the reporting system" diff --git a/bc_obps/reporting/models/report_new_entrant_production.py b/bc_obps/reporting/models/report_new_entrant_production.py new file mode 100644 index 0000000000..f005a7646f --- /dev/null +++ b/bc_obps/reporting/models/report_new_entrant_production.py @@ -0,0 +1,30 @@ +from django.db import models +from registration.models import RegulatedProduct +from registration.models.time_stamped_model import TimeStampedModel +from reporting.models.report_new_entrant import ReportNewEntrant + + +class ReportNewEntrantProduction(TimeStampedModel): + product = models.ForeignKey( + RegulatedProduct, + on_delete=models.CASCADE, + related_name="new_entrant_productions", + db_comment="The regulated product associated with this production record", + ) + report_new_entrant = models.ForeignKey( + ReportNewEntrant, + on_delete=models.CASCADE, + related_name="productions", + db_comment="The new entrant report to which this production record belongs", + ) + production_amount = models.IntegerField( + blank=True, + null=True, + default=0, + db_comment="The amount of production associated with this report", + ) + + class Meta: + db_table = 'erc"."report_new_entrant_production' + app_label = 'reporting' + db_table_comment = "Table for storing production data related to new entrant emissions reporting" diff --git a/bc_obps/reporting/schema/report_regulated_products.py b/bc_obps/reporting/schema/report_regulated_products.py new file mode 100644 index 0000000000..cffc240962 --- /dev/null +++ b/bc_obps/reporting/schema/report_regulated_products.py @@ -0,0 +1,6 @@ +from ninja import Schema + + +class RegulatedProductOut(Schema): + id: int + name: str diff --git a/bc_obps/service/report_service.py b/bc_obps/service/report_service.py index c9e893a82e..9d5f783761 100644 --- a/bc_obps/service/report_service.py +++ b/bc_obps/service/report_service.py @@ -1,3 +1,4 @@ +from typing import List from uuid import UUID from django.db import transaction from registration.models import Activity, RegulatedProduct @@ -7,6 +8,7 @@ from reporting.models.report_operation import ReportOperation from reporting.models.report_version import ReportVersion from reporting.schema.report_operation import ReportOperationIn +from reporting.schema.report_regulated_products import RegulatedProductOut from service.data_access_service.facility_service import FacilityDataAccessService from service.data_access_service.report_service import ReportDataAccessService from service.data_access_service.reporting_year import ReportingYearDataAccessService @@ -102,3 +104,14 @@ def save_report_operation(cls, report_version_id: int, data: ReportOperationIn) report_operation.save() return report_operation + + @classmethod + def get_regulated_products_by_version_id(cls, version_id: int) -> List[RegulatedProductOut]: + # Fetch the ReportOperation by version ID + report_operation = ReportOperation.objects.get(report_version_id=version_id) + + # Retrieve associated regulated products + regulated_products = report_operation.regulated_products.all() + + # Map to the output schema (assuming RegulatedProductOut has a 'name' field) + return [RegulatedProductOut(id=product.id, name=product.name) for product in regulated_products] diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx index 30fe09076d..cd3c0b169e 100644 --- a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx @@ -1,15 +1,21 @@ import { Suspense } from "react"; import Loading from "@bciers/components/loading/SkeletonForm"; import NewEntrantInformationForm from "@reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm"; +import { getReportProducts } from "@reporting/src/app/utils/getReportProducts"; export default async function NewEntrantInformation({ versionId, }: { versionId: number; }) { + const reportProducts = await getReportProducts(versionId); + return ( }> - + ); } diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx index ea4d9ca0b0..112855ba8b 100644 --- a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx @@ -16,10 +16,12 @@ const cancelUrl = "/reports"; interface AdditionalReportingDataProps { versionId: number; + reportProducts: []; } export default function NewEntrantInformationForm({ versionId, + reportProducts, }: AdditionalReportingDataProps) { const [formData, setFormData] = useState(); diff --git a/bciers/apps/reporting/src/app/utils/getReportProducts.ts b/bciers/apps/reporting/src/app/utils/getReportProducts.ts new file mode 100644 index 0000000000..d45b01e78d --- /dev/null +++ b/bciers/apps/reporting/src/app/utils/getReportProducts.ts @@ -0,0 +1,12 @@ +import { actionHandler } from "@bciers/actions"; +export async function getReportProducts(version_id: number) { + let response = await actionHandler( + `reporting/report-version/${version_id}/regulated-products`, + "GET", + `reporting/report-version/${version_id}/regulated-products`, + ); + + if (response && !response.error) { + return response; + } +} diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx index a52c382dd8..df4d2dd962 100644 --- a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx +++ b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx @@ -1,5 +1,6 @@ import { Typography } from "@mui/material"; import { BC_GOV_BACKGROUND_COLOR_BLUE } from "@bciers/styles"; +import { WidgetProps } from "@rjsf/utils"; export const newEntrantInfo = ( <> ); + +const ProductionDataTitleWidget: React.FC = ({ id, value }) => { + return ( +
+ Product: {value} +
+ ); +}; diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts index 60dc7e01bd..2bb6180c67 100644 --- a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts +++ b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts @@ -11,7 +11,7 @@ import checkboxWidget from "@bciers/components/form/widgets/CheckboxWidget"; export const newEntrantInformationSchema: RJSFSchema = { type: "object", - title: "Additional Reporting Data", + title: "New Entrant Information", properties: { purpose_note: { type: "object", readOnly: true }, date_of_authorization: { @@ -115,7 +115,7 @@ export const newEntrantInformationSchema: RJSFSchema = { export const newEntrantInformationUiSchema = { "ui:FieldTemplate": FieldTemplate, "ui:classNames": "form-heading-label", - "ui:options": { label: false }, + "ui:order": [ "purpose_note", "date_of_authorization", @@ -195,3 +195,5 @@ export const newEntrantInformationUiSchema = { }, }, }; + +const getUpdatedSchema = () => {}; From 64cf77c676821bd5fa83343b33d370e0e0524be2 Mon Sep 17 00:00:00 2001 From: ayeshmcg Date: Tue, 5 Nov 2024 12:13:16 -0800 Subject: [PATCH 4/6] chore:added schema and fixed model --- bc_obps/reporting/api/reports.py | 8 +- ...tnewentrant_reportnewentrantproduction.py} | 12 +- .../reporting/models/report_new_entrant.py | 6 +- .../NewEntrantInformation.tsx | 4 +- .../NewEntrantInformationForm.tsx | 14 +- .../components/products/ProductionData.tsx | 2 +- .../data/jsonSchema/newEntrantInformation.tsx | 252 ++++++++++++++++++ .../additionalMessage.tsx | 24 -- .../newEntrantInformation.ts | 199 -------------- .../src/data/jsonSchema/productionData.tsx | 5 +- erd_diagrams/erd_reporting.md | 48 ++++ 11 files changed, 327 insertions(+), 247 deletions(-) rename bc_obps/reporting/migrations/{0027_reportnewentrant_reportnewentrantproduction.py => 0030_reportnewentrant_reportnewentrantproduction.py} (95%) create mode 100644 bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx delete mode 100644 bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx delete mode 100644 bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts diff --git a/bc_obps/reporting/api/reports.py b/bc_obps/reporting/api/reports.py index bf2132cddf..dc48fd9b65 100644 --- a/bc_obps/reporting/api/reports.py +++ b/bc_obps/reporting/api/reports.py @@ -40,7 +40,7 @@ def start_report(request: HttpRequest, payload: StartReportIn) -> Tuple[Literal[ ) @handle_http_errors() def get_report_operation_by_version_id( - request: HttpRequest, version_id: int + request: HttpRequest, version_id: int ) -> Tuple[Literal[200], ReportOperationOut]: report_operation = ReportService.get_report_operation_by_version_id(version_id) return 200, report_operation # type: ignore @@ -56,7 +56,7 @@ def get_report_operation_by_version_id( ) @handle_http_errors() def save_report( - request: HttpRequest, version_id: int, payload: ReportOperationIn + request: HttpRequest, version_id: int, payload: ReportOperationIn ) -> Tuple[Literal[201], ReportOperationOut]: report_operation = ReportService.save_report_operation(version_id, payload) return 201, report_operation # type: ignore @@ -75,7 +75,7 @@ def get_reporting_year(request: HttpRequest) -> Tuple[Literal[200], ReportingYea @router.get( - "/report-version/{version_id}/regulated-products", + "/report-version/{version_id}/report-operation/regulated-products", response={200: List[RegulatedProductOut], custom_codes_4xx: Message}, tags=EMISSIONS_REPORT_TAGS, description="""Retrieves all regulated products associated with a report operation identified by its version ID.""", @@ -83,7 +83,7 @@ def get_reporting_year(request: HttpRequest) -> Tuple[Literal[200], ReportingYea ) @handle_http_errors() def get_regulated_products_by_version_id( - request: HttpRequest, version_id: int + request: HttpRequest, version_id: int ) -> Tuple[Literal[200], List[RegulatedProductOut]]: regulated_products = ReportService.get_regulated_products_by_version_id(version_id) return 200, regulated_products diff --git a/bc_obps/reporting/migrations/0027_reportnewentrant_reportnewentrantproduction.py b/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py similarity index 95% rename from bc_obps/reporting/migrations/0027_reportnewentrant_reportnewentrantproduction.py rename to bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py index 3bafd7c3d3..273a991ee8 100644 --- a/bc_obps/reporting/migrations/0027_reportnewentrant_reportnewentrantproduction.py +++ b/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.9 on 2024-11-05 06:02 +# Generated by Django 5.0.9 on 2024-11-05 20:07 import django.db.models.deletion from django.db import migrations, models @@ -7,8 +7,8 @@ class Migration(migrations.Migration): dependencies = [ - ('registration', '0048_bcobpsregulatedoperation_issued_by_and_more'), - ('reporting', '0026_reportmethodology_methodology'), + ('registration', '0051_bcgreenhousegasid_historicalbcgreenhousegasid'), + ('reporting', '0029_remove_facilityreport_products_reportproduct_and_more'), ] operations = [ @@ -29,10 +29,10 @@ class Migration(migrations.Migration): to='reporting.reportversion', ), ), - ('authorization_date', models.DateTimeField(db_comment='Date of authorization for emission reporting')), + ('authorization_date', models.DateField(db_comment='Date of authorization for emission reporting')), ( 'first_shipment_date', - models.DateTimeField( + models.DateField( blank=True, db_comment='Date of the first shipment related to this report (if applicable)', null=True, @@ -40,7 +40,7 @@ class Migration(migrations.Migration): ), ( 'new_entrant_period_start', - models.DateTimeField( + models.DateField( blank=True, db_comment='Start date of the new entrant reporting period', null=True ), ), diff --git a/bc_obps/reporting/models/report_new_entrant.py b/bc_obps/reporting/models/report_new_entrant.py index e5cdbfcb22..8274eb1cfc 100644 --- a/bc_obps/reporting/models/report_new_entrant.py +++ b/bc_obps/reporting/models/report_new_entrant.py @@ -11,15 +11,15 @@ class ReportNewEntrant(TimeStampedModel): db_comment="The associated report version for this new entrant record", primary_key=True, ) - authorization_date = models.DateTimeField( + authorization_date = models.DateField( db_comment="Date of authorization for emission reporting", ) - first_shipment_date = models.DateTimeField( + first_shipment_date = models.DateField( blank=True, null=True, db_comment="Date of the first shipment related to this report (if applicable)", ) - new_entrant_period_start = models.DateTimeField( + new_entrant_period_start = models.DateField( blank=True, null=True, db_comment="Start date of the new entrant reporting period", diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx index cd3c0b169e..d8d2f28124 100644 --- a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx @@ -1,6 +1,6 @@ import { Suspense } from "react"; import Loading from "@bciers/components/loading/SkeletonForm"; -import NewEntrantInformationForm from "@reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm"; +import NewEntrantInformationForm from "./NewEntrantInformationForm"; import { getReportProducts } from "@reporting/src/app/utils/getReportProducts"; export default async function NewEntrantInformation({ @@ -14,7 +14,7 @@ export default async function NewEntrantInformation({ }> ); diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx index 112855ba8b..007924bf47 100644 --- a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx @@ -7,21 +7,21 @@ import { useRouter } from "next/navigation"; import { actionHandler } from "@bciers/actions"; import { - newEntrantInformationSchema, - newEntrantInformationUiSchema, -} from "@reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation"; + createNewEntrantInformationSchema, + createNewEntrantInformationUiSchema, +} from "@reporting/src/data/jsonSchema/newEntrantInformation"; const baseUrl = "/reports"; const cancelUrl = "/reports"; interface AdditionalReportingDataProps { versionId: number; - reportProducts: []; + products: []; } export default function NewEntrantInformationForm({ versionId, - reportProducts, + products, }: AdditionalReportingDataProps) { const [formData, setFormData] = useState(); @@ -72,8 +72,8 @@ export default function NewEntrantInformationForm({ "Sign-off & Submit", ]} taskListElements={taskListElements} - schema={newEntrantInformationSchema} - uiSchema={newEntrantInformationUiSchema} + schema={createNewEntrantInformationSchema(products)} + uiSchema={createNewEntrantInformationUiSchema(products)} formData={formData} baseUrl={baseUrl} cancelUrl={cancelUrl} diff --git a/bciers/apps/reporting/src/app/components/products/ProductionData.tsx b/bciers/apps/reporting/src/app/components/products/ProductionData.tsx index 8208b6ae1c..8d9b95b591 100644 --- a/bciers/apps/reporting/src/app/components/products/ProductionData.tsx +++ b/bciers/apps/reporting/src/app/components/products/ProductionData.tsx @@ -32,7 +32,7 @@ const ProductionData: React.FC = async ({ report_version_id, facility_id, ); - const taskListElements = await getFacilitiesInformationTaskList( + const taskListElements = getFacilitiesInformationTaskList( report_version_id, facility_id, orderedActivities, diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx new file mode 100644 index 0000000000..9c5d0d786b --- /dev/null +++ b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx @@ -0,0 +1,252 @@ +import { RJSFSchema, UiSchema, WidgetProps } from "@rjsf/utils"; +import FieldTemplate from "@bciers/components/form/fields/FieldTemplate"; +import { + InlineFieldTemplate, + TitleOnlyFieldTemplate, +} from "@bciers/components/form/fields"; +import SectionFieldTemplate from "@bciers/components/form/fields/SectionFieldTemplate"; +import { DateWidget } from "@bciers/components/form/widgets"; +import checkboxWidget from "@bciers/components/form/widgets/CheckboxWidget"; +import { BC_GOV_BACKGROUND_COLOR_BLUE } from "@bciers/styles"; +import { Typography } from "@mui/material"; + +const ProductionDataTitleWidget: React.FC = ({ id, value }) => { + return ( +
+ Product: {value} +
+ ); +}; + +export const newEntrantInfo = ( + <> + + This section applies to operations that fall under{" "} + new entrant category. + + +); +type Product = { + id: number; + name: string; +}; + +export const createNewEntrantInformationSchema = ( + selectedProducts: Product[], +) => + ({ + type: "object", + title: "New Entrant Information", + properties: { + purpose_note: { type: "object", readOnly: true }, + date_of_authorization: { + type: "string", + title: "Date of authorization", + }, + date_of_first_shipment: { + type: "string", + title: "Date of first shipment", + }, + date_of_new_entrant_period_began: { + type: "string", + title: "Date new entrant period began", + }, + assertion_statement: { + type: "boolean", + title: + "I certify that this operation was a reporting operation on the date that the application for designation as a new entrant was submitted to the Director under GGIRCA.", + default: false, + }, + ...selectedProducts.reduce( + (acc, product) => ({ + ...acc, + [`product_${product.id}`]: { + type: "object", + title: `Product: ${product.name}`, + properties: { + production_after_new_entrant: { + type: "number", + title: "Production after new entrant period began", + }, + }, + }, + }), + {}, + ), + + emission_after_new_entrant: { + type: "object", + title: "Emission categories after new entrant period began", + properties: { + flaring_emissions: { + type: "number", + title: "Flaring emissions", + }, + fugitive_emissions: { + type: "number", + title: "Fugitive emissions", + }, + industrial_process_emissions: { + type: "number", + title: "Industrial process emissions", + }, + on_site_transportation_emissions: { + type: "number", + title: "On-site transportation emissions", + }, + stationary_fuel_combustion_emissions: { + type: "number", + title: "Stationary fuel combustion emissions", + }, + venting_emissions_useful: { + type: "number", + title: "Venting emissions - useful", + }, + venting_emissions_non_useful: { + type: "number", + title: "Venting emissions - non-useful", + }, + emissions_from_waste: { + type: "number", + title: "Emissions from waste", + }, + emissions_from_wastewater: { + type: "number", + title: "Emissions from wastewater", + }, + }, + }, + emission_excluded_by_fuel_type: { + type: "object", + title: "Emissions excluded by fuel type", + properties: { + co2_emissions_from_excluded_woody_biomass: { + type: "number", + title: "CO2 emissions from excluded woody biomass", + }, + other_emissions_from_excluded_biomasss: { + type: "number", + title: "Other emissions from excluded biomass", + }, + emissions_from_excluded_non_biomass: { + type: "number", + title: "Emissions from excluded non-biomass", + }, + }, + }, + other_excluded_emissions: { + type: "object", + title: "Other excluded emissions", + properties: { + emissions_from_line_tracing: { + type: "number", + title: + "Emissions from line tracing and non-processing and non-compression activities", + }, + emissions_from_fat_oil: { + type: "number", + title: + "Emissions from fat, oil and grease collection, refining and storage ", + }, + }, + }, + }, + }) as RJSFSchema; + +export const createNewEntrantInformationUiSchema = ( + selectedProducts: Product[], +): UiSchema => ({ + "ui:FieldTemplate": FieldTemplate, + "ui:classNames": "form-heading-label", + + purpose_note: { + "ui:FieldTemplate": TitleOnlyFieldTemplate, + "ui:title": newEntrantInfo, + }, + + assertion_statement: { + "ui:widget": checkboxWidget, + }, + + date_of_authorization: { + "ui:widget": DateWidget, + }, + + date_of_first_shipment: { + "ui:widget": DateWidget, + }, + + date_of_new_entrant_period_began: { + "ui:widget": DateWidget, + }, + + ...selectedProducts.reduce<{ [key: string]: any }>((acc, product) => { + acc[`product_${product.id}`] = { + "ui:FieldTemplate": SectionFieldTemplate, + "ui:widget": ProductionDataTitleWidget, + production_after_new_entrant: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }; + return acc; + }, {}), + + emission_after_new_entrant: { + "ui:FieldTemplate": SectionFieldTemplate, + flaring_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + fugitive_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + industrial_process_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + on_site_transportation_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + stationary_fuel_combustion_emissions: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + venting_emissions_useful: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + venting_emissions_non_useful: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_waste: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_wastewater: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }, + + emission_excluded_by_fuel_type: { + "ui:FieldTemplate": SectionFieldTemplate, + co2_emissions_from_excluded_woody_biomass: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + other_emissions_from_excluded_biomasss: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_excluded_non_biomass: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }, + + other_excluded_emissions: { + "ui:FieldTemplate": SectionFieldTemplate, + emissions_from_line_tracing: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + emissions_from_fat_oil: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }, +}); diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx deleted file mode 100644 index df4d2dd962..0000000000 --- a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Typography } from "@mui/material"; -import { BC_GOV_BACKGROUND_COLOR_BLUE } from "@bciers/styles"; -import { WidgetProps } from "@rjsf/utils"; -export const newEntrantInfo = ( - <> - - This section applies to operations that fall under{" "} - new entrant category. - - -); - -const ProductionDataTitleWidget: React.FC = ({ id, value }) => { - return ( -
- Product: {value} -
- ); -}; diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts deleted file mode 100644 index 2bb6180c67..0000000000 --- a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation/newEntrantInformation.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { RJSFSchema } from "@rjsf/utils"; -import FieldTemplate from "@bciers/components/form/fields/FieldTemplate"; -import { - InlineFieldTemplate, - TitleOnlyFieldTemplate, -} from "@bciers/components/form/fields"; -import SectionFieldTemplate from "@bciers/components/form/fields/SectionFieldTemplate"; -import { DateWidget } from "@bciers/components/form/widgets"; -import { newEntrantInfo } from "@reporting/src/data/jsonSchema/newEntrantInformation/additionalMessage"; -import checkboxWidget from "@bciers/components/form/widgets/CheckboxWidget"; - -export const newEntrantInformationSchema: RJSFSchema = { - type: "object", - title: "New Entrant Information", - properties: { - purpose_note: { type: "object", readOnly: true }, - date_of_authorization: { - type: "string", - title: "Date of authorization", - }, - date_of_first_shipment: { - type: "string", - title: "Date of first shipment", - }, - date_of_new_entrant_period_began: { - type: "string", - title: "Date new entrant period began", - }, - assertion_statement: { - type: "boolean", - title: - "I certify that this operation was a reporting operation on the date that the application for designation as a new entrant was submitted to the Director under GGIRCA.", - default: false, - }, - - emission_after_new_entrant: { - type: "object", - title: "Emission categories after new entrant period began", - properties: { - flaring_emissions: { - type: "number", - title: "Flaring emissions", - }, - fugitive_emissions: { - type: "number", - title: "Fugitive emissions", - }, - industrial_process_emissions: { - type: "number", - title: "Industrial process emissions", - }, - on_site_transportation_emissions: { - type: "number", - title: "On-site transportation emissions", - }, - stationary_fuel_combustion_emissions: { - type: "number", - title: "Stationary fuel combustion emissions", - }, - venting_emissions_useful: { - type: "number", - title: "Venting emissions - useful", - }, - venting_emissions_non_useful: { - type: "number", - title: "Venting emissions - non-useful", - }, - emissions_from_waste: { - type: "number", - title: "Emissions from waste", - }, - emissions_from_wastewater: { - type: "number", - title: "Emissions from wastewater", - }, - }, - }, - emission_excluded_by_fuel_type: { - type: "object", - title: "Emissions excluded by fuel type", - properties: { - co2_emissions_from_excluded_woody_biomass: { - type: "number", - title: "CO2 emissions from excluded woody biomass", - }, - other_emissions_from_excluded_biomasss: { - type: "number", - title: "Other emissions from excluded biomass", - }, - emissions_from_excluded_non_biomass: { - type: "number", - title: "Emissions from excluded non-biomass", - }, - }, - }, - other_excluded_emissions: { - type: "object", - title: "Other excluded emissions", - properties: { - emissions_from_line_tracing: { - type: "number", - title: - "Emissions from line tracing and non-processing and non-compression activities", - }, - emissions_from_fat_oil: { - type: "number", - title: - "Emissions from fat, oil and grease collection, refining and storage ", - }, - }, - }, - }, -}; - -export const newEntrantInformationUiSchema = { - "ui:FieldTemplate": FieldTemplate, - "ui:classNames": "form-heading-label", - - "ui:order": [ - "purpose_note", - "date_of_authorization", - "date_of_first_shipment", - "date_of_new_entrant_period_began", - "assertion_statement", - "emission_after_new_entrant", - "emission_excluded_by_fuel_type", - "other_excluded_emissions", - ], - purpose_note: { - "ui:FieldTemplate": TitleOnlyFieldTemplate, - "ui:title": newEntrantInfo, - }, - assertion_statement: { - "ui:widget": checkboxWidget, - }, - date_of_authorization: { - "ui:widget": DateWidget, - }, - - date_of_first_shipment: { - "ui:widget": DateWidget, - }, - date_of_new_entrant_period_began: { - "ui:widget": DateWidget, - }, - emission_after_new_entrant: { - "ui:FieldTemplate": SectionFieldTemplate, - flaring_emissions: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - fugitive_emissions: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - industrial_process_emissions: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - on_site_transportation_emissions: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - stationary_fuel_combustion_emissions: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - venting_emissions_useful: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - venting_emissions_non_useful: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - emissions_from_waste: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - emissions_from_wastewater: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - }, - emission_excluded_by_fuel_type: { - "ui:FieldTemplate": SectionFieldTemplate, - co2_emissions_from_excluded_woody_biomass: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - other_emissions_from_excluded_biomasss: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - emissions_from_excluded_non_biomass: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - }, - other_excluded_emissions: { - "ui:FieldTemplate": SectionFieldTemplate, - emissions_from_line_tracing: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - emissions_from_fat_oil: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - }, -}; - -const getUpdatedSchema = () => {}; diff --git a/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx b/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx index 4a05ecd4e0..7074ad0354 100644 --- a/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx +++ b/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx @@ -6,7 +6,10 @@ import { import { ReadOnlyWidget } from "@bciers/components/form/widgets/readOnly"; import { RJSFSchema, UiSchema, WidgetProps } from "@rjsf/utils"; -const ProductionDataTitleWidget: React.FC = ({ id, value }) => { +export const ProductionDataTitleWidget: React.FC = ({ + id, + value, +}) => { return (
Product: {value} diff --git a/erd_diagrams/erd_reporting.md b/erd_diagrams/erd_reporting.md index 67f0efb551..3dc84f5477 100644 --- a/erd_diagrams/erd_reporting.md +++ b/erd_diagrams/erd_reporting.md @@ -277,6 +277,45 @@ EmissionCategoryMapping { ForeignKey activity ForeignKey source_type } +ReportNewEntrant { + ForeignKey created_by + DateTimeField created_at + ForeignKey updated_by + DateTimeField updated_at + ForeignKey archived_by + DateTimeField archived_at + OneToOneField report_version + DateField authorization_date + DateField first_shipment_date + DateField new_entrant_period_start + BooleanField assertion_statement_certified + IntegerField flaring_emissions + IntegerField fugitive_emissions + IntegerField industrial_process_emissions + IntegerField on_site_transportation_emissions + IntegerField stationary_fuel_combustion_emissions + IntegerField venting_emissions_useful + IntegerField venting_emissions_non_useful + IntegerField emissions_from_waste + IntegerField emissions_from_wastewater + IntegerField co2_emissions_from_excluded_woody_biomass + IntegerField other_emissions_from_excluded_biomass + IntegerField emissions_from_excluded_non_biomass + IntegerField emissions_from_line_tracing + IntegerField emissions_from_fat_oil +} +ReportNewEntrantProduction { + BigAutoField id + ForeignKey created_by + DateTimeField created_at + ForeignKey updated_by + DateTimeField updated_at + ForeignKey archived_by + DateTimeField archived_at + ForeignKey product + ForeignKey report_new_entrant + IntegerField production_amount +} ReportNonAttributableEmissions { BigAutoField id ForeignKey created_by @@ -410,6 +449,15 @@ ReportAdditionalData ||--|| ReportVersion : report_version EmissionCategoryMapping }|--|| EmissionCategory : emission_category EmissionCategoryMapping }|--|| Activity : activity EmissionCategoryMapping }|--|| SourceType : source_type +ReportNewEntrant }|--|| User : created_by +ReportNewEntrant }|--|| User : updated_by +ReportNewEntrant }|--|| User : archived_by +ReportNewEntrant ||--|| ReportVersion : report_version +ReportNewEntrantProduction }|--|| User : created_by +ReportNewEntrantProduction }|--|| User : updated_by +ReportNewEntrantProduction }|--|| User : archived_by +ReportNewEntrantProduction }|--|| RegulatedProduct : product +ReportNewEntrantProduction }|--|| ReportNewEntrant : report_new_entrant ReportNonAttributableEmissions }|--|| User : created_by ReportNonAttributableEmissions }|--|| User : updated_by ReportNonAttributableEmissions }|--|| User : archived_by From e25baed71feb6603e1371d62c3e85f92eeed76ec Mon Sep 17 00:00:00 2001 From: ayeshmcg Date: Thu, 7 Nov 2024 18:31:37 -0800 Subject: [PATCH 5/6] chore: fixed components and test --- .../tests/models/test_regulated_product.py | 1 + .../registration/tests/models/test_user.py | 6 + bc_obps/reporting/api/__init__.py | 2 + bc_obps/reporting/api/production_data.py | 2 +- .../reporting/api/report_new_entrant_data.py | 45 +++++++ ...rtnewentrant_reportnewentrantproduction.py | 4 +- .../reporting/models/report_new_entrant.py | 4 +- .../reporting/schema/report_new_entrant.py | 70 +++++++++++ .../service/report_new_entrant_service.py | 89 +++++++++++++ .../tests/models/test_report_new_entrant.py | 32 +++++ .../test_report_new_entrant_production.py | 16 +++ .../tests/models/test_report_version.py | 1 + .../tests/utils/report_data_bakers.py | 25 ++++ .../NewEntrantInformation.tsx | 87 ++++++++++++- .../NewEntrantInformationForm.tsx | 49 +++++--- .../src/app/utils/getNewEntrantData.ts | 13 ++ .../src/app/utils/getReportProducts.ts | 12 -- .../data/jsonSchema/newEntrantInformation.tsx | 103 ++++++++++----- .../src/data/jsonSchema/productionData.tsx | 5 +- .../NewEntrantInformation.test.tsx | 118 ++++++++++++++++++ .../src/form/widgets/CheckboxWidget.tsx | 3 +- .../src/form/widgets/DateWidget.tsx | 14 ++- erd_diagrams/erd_reporting.md | 2 +- 23 files changed, 626 insertions(+), 77 deletions(-) create mode 100644 bc_obps/reporting/api/report_new_entrant_data.py create mode 100644 bc_obps/reporting/schema/report_new_entrant.py create mode 100644 bc_obps/reporting/service/report_new_entrant_service.py create mode 100644 bc_obps/reporting/tests/models/test_report_new_entrant.py create mode 100644 bc_obps/reporting/tests/models/test_report_new_entrant_production.py create mode 100644 bciers/apps/reporting/src/app/utils/getNewEntrantData.ts delete mode 100644 bciers/apps/reporting/src/app/utils/getReportProducts.ts create mode 100644 bciers/apps/reporting/src/tests/components/additionalInformation/NewEntrantInformation.test.tsx diff --git a/bc_obps/registration/tests/models/test_regulated_product.py b/bc_obps/registration/tests/models/test_regulated_product.py index b5e40e7724..2c75e10731 100644 --- a/bc_obps/registration/tests/models/test_regulated_product.py +++ b/bc_obps/registration/tests/models/test_regulated_product.py @@ -10,6 +10,7 @@ def setUpTestData(cls): ("name", "name", 1000, None), ("operations", "operation", None, None), ("report_products", "report product", None, 0), + ("new_entrant_productions", "report new entrant production", None, 0), ] cls.test_object = RegulatedProduct.objects.create( name="test product", diff --git a/bc_obps/registration/tests/models/test_user.py b/bc_obps/registration/tests/models/test_user.py index 656819b6a5..04507c696e 100644 --- a/bc_obps/registration/tests/models/test_user.py +++ b/bc_obps/registration/tests/models/test_user.py @@ -137,6 +137,12 @@ def setUpTestData(cls): ("reportproduct_created", "report product", None, None), ("reportproduct_updated", "report product", None, None), ("reportproduct_archived", "report product", None, None), + ("reportnewentrantproduction_created", "report new entrant production", None, None), + ("reportnewentrantproduction_updated", "report new entrant production", None, None), + ("reportnewentrantproduction_archived", "report new entrant production", None, None), + ("reportnewentrant_created", "report new entrant", None, None), + ("reportnewentrant_updated", "report new entrant", None, None), + ("reportnewentrant_archived", "report new entrant", None, None), ] def test_unique_user_guid_and_business_guid_constraint(self): diff --git a/bc_obps/reporting/api/__init__.py b/bc_obps/reporting/api/__init__.py index 63108a2275..aa37dfe71b 100644 --- a/bc_obps/reporting/api/__init__.py +++ b/bc_obps/reporting/api/__init__.py @@ -14,5 +14,7 @@ from .gas_type import get_gas_type from .emission_category import get_emission_category from .production_data import save_production_data +from .report_new_entrant_data import save_new_entrant_data +from .report_new_entrant_data import get_new_entrant_data from .report_non_attributable_emissions import save_report from .report_activity import save_report_activity_data, load_report_activity_data diff --git a/bc_obps/reporting/api/production_data.py b/bc_obps/reporting/api/production_data.py index 1f92f6eb3b..202464aa05 100644 --- a/bc_obps/reporting/api/production_data.py +++ b/bc_obps/reporting/api/production_data.py @@ -44,7 +44,7 @@ def save_production_data( tags=EMISSIONS_REPORT_TAGS, description="""Retrieves the data for the production data page from the multiple ReportProduct rows""", exclude_none=True, - auth=authorize("approved_industry_user"), + # auth=authorize("approved_industry_user"), ) @handle_http_errors() def load_production_data(request: HttpRequest, report_version_id: int, facility_id: UUID) -> Tuple[Literal[200], dict]: diff --git a/bc_obps/reporting/api/report_new_entrant_data.py b/bc_obps/reporting/api/report_new_entrant_data.py new file mode 100644 index 0000000000..ae630bea73 --- /dev/null +++ b/bc_obps/reporting/api/report_new_entrant_data.py @@ -0,0 +1,45 @@ +from typing import Literal, Tuple +from django.http import HttpRequest +from registration.decorators import handle_http_errors +from reporting.schema.generic import Message +from service.error_service.custom_codes_4xx import custom_codes_4xx +from service.report_service import ReportService +from .router import router +from ..schema.report_new_entrant import ReportNewEntrantSchemaIn, ReportNewEntrantDataOut +from ..service.report_new_entrant_service import ReportNewEntrantService + + +@router.get( + "report-version/{report_version_id}/new-entrant-data", + response={200: ReportNewEntrantDataOut}, + tags=["Emissions Report"], +) +def get_new_entrant_data(request: HttpRequest, report_version_id: int) -> Tuple[Literal[200], dict]: + report_new_entrant = ReportNewEntrantService.get_new_entrant_data(report_version_id) or {} + regulated_products = ReportService.get_regulated_products_by_version_id(report_version_id) or {} + + response_data = { + "regulated_products": regulated_products, + "report_new_entrant_data": report_new_entrant, + } + print('response_data', response_data) + + return 200, response_data + + +@router.post( + "report-version/{report_version_id}/new-entrant-data", + response={200: int, custom_codes_4xx: Message}, + tags=["Emissions Report"], + description="Saves the data for the new entrant report", + # auth=authorize("approved_industry_user"), +) +@handle_http_errors() +def save_new_entrant_data( + request: HttpRequest, + report_version_id: int, + payload: ReportNewEntrantSchemaIn, +) -> int: + ReportNewEntrantService.save_new_entrant_data(report_version_id, payload) + + return 200 diff --git a/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py b/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py index 273a991ee8..cfc0cd7141 100644 --- a/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py +++ b/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.9 on 2024-11-05 20:07 +# Generated by Django 5.0.9 on 2024-11-07 17:14 import django.db.models.deletion from django.db import migrations, models @@ -45,7 +45,7 @@ class Migration(migrations.Migration): ), ), ( - 'assertion_statement_certified', + 'assertion_statement', models.BooleanField( blank=True, db_comment='Indicates if the assertion statement is certified', null=True ), diff --git a/bc_obps/reporting/models/report_new_entrant.py b/bc_obps/reporting/models/report_new_entrant.py index 8274eb1cfc..193cebfed8 100644 --- a/bc_obps/reporting/models/report_new_entrant.py +++ b/bc_obps/reporting/models/report_new_entrant.py @@ -6,7 +6,7 @@ class ReportNewEntrant(TimeStampedModel): report_version = models.OneToOneField( ReportVersion, - on_delete=models.PROTECT, + on_delete=models.CASCADE, related_name="report_new_entrant", db_comment="The associated report version for this new entrant record", primary_key=True, @@ -24,7 +24,7 @@ class ReportNewEntrant(TimeStampedModel): null=True, db_comment="Start date of the new entrant reporting period", ) - assertion_statement_certified = models.BooleanField( + assertion_statement = models.BooleanField( blank=True, null=True, db_comment="Indicates if the assertion statement is certified", diff --git a/bc_obps/reporting/schema/report_new_entrant.py b/bc_obps/reporting/schema/report_new_entrant.py new file mode 100644 index 0000000000..d94cb5dff8 --- /dev/null +++ b/bc_obps/reporting/schema/report_new_entrant.py @@ -0,0 +1,70 @@ +from ninja import Schema +from pydantic import BaseModel +from typing import Dict, Optional, List + +from registration.schema.v1 import RegulatedProductSchema + + +class EmissionAfterNewEntrantSchema(BaseModel): + flaring_emissions: int + fugitive_emissions: int + industrial_process_emissions: int + on_site_transportation_emissions: int + stationary_fuel_combustion_emissions: int + venting_emissions_useful: int + venting_emissions_non_useful: int + emissions_from_waste: int + emissions_from_wastewater: int + + +class EmissionExcludedByFuelTypeSchema(BaseModel): + co2_emissions_from_excluded_woody_biomass: int + other_emissions_from_excluded_biomass: int + emissions_from_excluded_non_biomass: int + + +class OtherExcludedEmissionsSchema(BaseModel): + emissions_from_line_tracing: int + emissions_from_fat_oil: int + + +class ProductSchema(BaseModel): + production_amount: int + + +class ReportNewEntrantSchemaIn(BaseModel): + assertion_statement: bool + date_of_authorization: str + date_of_first_shipment: Optional[str] + date_of_new_entrant_period_began: Optional[str] + products: Dict[int, ProductSchema] + emission_after_new_entrant: EmissionAfterNewEntrantSchema + emission_excluded_by_fuel_type: EmissionExcludedByFuelTypeSchema + other_excluded_emissions: OtherExcludedEmissionsSchema + + +class ReportNewEntrantSchemaOut(BaseModel): + authorization_date: Optional[str] = None + first_shipment_date: Optional[str] = None + new_entrant_period_start: Optional[str] = None + assertion_statement: Optional[bool] = None + flaring_emissions: Optional[int] = None + fugitive_emissions: Optional[int] = None + industrial_process_emissions: Optional[int] = None + on_site_transportation_emissions: Optional[int] = None + stationary_fuel_combustion_emissions: Optional[int] = None + venting_emissions_useful: Optional[int] = None + venting_emissions_non_useful: Optional[int] = None + emissions_from_waste: Optional[int] = None + emissions_from_wastewater: Optional[int] = None + co2_emissions_from_excluded_woody_biomass: Optional[int] = None + other_emissions_from_excluded_biomass: Optional[int] = None + emissions_from_excluded_non_biomass: Optional[int] = None + emissions_from_line_tracing: Optional[int] = None + emissions_from_fat_oil: Optional[int] = None + selected_products: Optional[List[Dict[int, Dict[str, int]]]] = None + + +class ReportNewEntrantDataOut(Schema): + regulated_products: List[RegulatedProductSchema] + report_new_entrant_data: ReportNewEntrantSchemaOut diff --git a/bc_obps/reporting/service/report_new_entrant_service.py b/bc_obps/reporting/service/report_new_entrant_service.py new file mode 100644 index 0000000000..4fa116d284 --- /dev/null +++ b/bc_obps/reporting/service/report_new_entrant_service.py @@ -0,0 +1,89 @@ +from datetime import date +from typing import Dict + +from django.db import transaction +from django.forms import model_to_dict + +from registration.models import RegulatedProduct +from reporting.models import ReportVersion, ReportNewEntrant, ReportNewEntrantProduction +from reporting.schema.report_new_entrant import ReportNewEntrantSchemaIn + + +class ReportNewEntrantService: + @classmethod + def get_new_entrant_data(cls, report_version_id: int) -> dict: + report_new_entrant = ReportNewEntrant.objects.filter(report_version_id=report_version_id).first() + + if not report_new_entrant: + return {} + + result_data: Dict = model_to_dict(report_new_entrant, exclude=['selected_products']) + + result_data['selected_products'] = [ + {production.product_id: {"production_amount": production.production_amount}} + for production in report_new_entrant.productions.all() + ] + + for key, value in result_data.items(): + if isinstance(value, date): + result_data[key] = value.isoformat() + + return result_data + + @classmethod + @transaction.atomic + def save_new_entrant_data( + cls, + report_version_id: int, + data: ReportNewEntrantSchemaIn, + ) -> None: + + report_version = ReportVersion.objects.get(pk=report_version_id) + + entrant_data = { + "authorization_date": data.date_of_authorization, + "first_shipment_date": data.date_of_first_shipment, + "new_entrant_period_start": data.date_of_new_entrant_period_began, + "assertion_statement": data.assertion_statement, + "flaring_emissions": data.emission_after_new_entrant.flaring_emissions, + "fugitive_emissions": data.emission_after_new_entrant.fugitive_emissions, + "industrial_process_emissions": data.emission_after_new_entrant.industrial_process_emissions, + "on_site_transportation_emissions": data.emission_after_new_entrant.on_site_transportation_emissions, + "stationary_fuel_combustion_emissions": data.emission_after_new_entrant.stationary_fuel_combustion_emissions, + "venting_emissions_useful": data.emission_after_new_entrant.venting_emissions_useful, + "venting_emissions_non_useful": data.emission_after_new_entrant.venting_emissions_non_useful, + "emissions_from_waste": data.emission_after_new_entrant.emissions_from_waste, + "emissions_from_wastewater": data.emission_after_new_entrant.emissions_from_wastewater, + "co2_emissions_from_excluded_woody_biomass": data.emission_excluded_by_fuel_type.co2_emissions_from_excluded_woody_biomass, + "other_emissions_from_excluded_biomass": data.emission_excluded_by_fuel_type.other_emissions_from_excluded_biomass, + "emissions_from_excluded_non_biomass": data.emission_excluded_by_fuel_type.emissions_from_excluded_non_biomass, + "emissions_from_line_tracing": data.other_excluded_emissions.emissions_from_line_tracing, + "emissions_from_fat_oil": data.other_excluded_emissions.emissions_from_fat_oil, + } + + report_new_entrant, _ = ReportNewEntrant.objects.update_or_create( + report_version=report_version, + defaults=entrant_data, + ) + + production_data = [ + {"product_id": product_id, "production_amount": details.production_amount} + for product_id, details in data.products.items() + ] + + product_ids = [entry["product_id"] for entry in production_data] + allowed_products = RegulatedProduct.objects.filter(id__in=product_ids).values_list("id", flat=True) + + if not all(prod_id in allowed_products for prod_id in product_ids): + raise ValueError("Invalid product IDs provided.") + + ReportNewEntrantProduction.objects.filter(report_new_entrant=report_new_entrant).exclude( + product_id__in=product_ids + ).delete() + + for prod_data in production_data: + ReportNewEntrantProduction.objects.update_or_create( + report_new_entrant=report_new_entrant, + product_id=prod_data["product_id"], + defaults={"production_amount": prod_data["production_amount"]}, + ) diff --git a/bc_obps/reporting/tests/models/test_report_new_entrant.py b/bc_obps/reporting/tests/models/test_report_new_entrant.py new file mode 100644 index 0000000000..31c078309e --- /dev/null +++ b/bc_obps/reporting/tests/models/test_report_new_entrant.py @@ -0,0 +1,32 @@ +from common.tests.utils.helpers import BaseTestCase +from reporting.tests.utils.report_data_bakers import report_new_entrant_baker +from registration.tests.constants import TIMESTAMP_COMMON_FIELDS + + +class ReportNewEntrantModelTest(BaseTestCase): + @classmethod + def setUpTestData(cls): + cls.test_object = report_new_entrant_baker() + cls.field_data = [ + *TIMESTAMP_COMMON_FIELDS, + ("report_version", "report version", None, None), + ("authorization_date", "authorization date", None, None), + ("first_shipment_date", "first shipment date", None, None), + ("new_entrant_period_start", "new entrant period start", None, None), + ("assertion_statement", "assertion statement", None, None), + ("flaring_emissions", "flaring emissions", None, None), + ("fugitive_emissions", "fugitive emissions", None, None), + ("industrial_process_emissions", "industrial process emissions", None, None), + ("on_site_transportation_emissions", "on site transportation emissions", None, None), + ("stationary_fuel_combustion_emissions", "stationary fuel combustion emissions", None, None), + ("venting_emissions_useful", "venting emissions useful", None, None), + ("venting_emissions_non_useful", "venting emissions non useful", None, None), + ("emissions_from_waste", "emissions from waste", None, None), + ("emissions_from_wastewater", "emissions from wastewater", None, None), + ("co2_emissions_from_excluded_woody_biomass", "co2 emissions from excluded woody biomass", None, None), + ("other_emissions_from_excluded_biomass", "other emissions from excluded biomass", None, None), + ("emissions_from_excluded_non_biomass", "emissions from excluded non biomass", None, None), + ("emissions_from_line_tracing", "emissions from line tracing", None, None), + ("emissions_from_fat_oil", "emissions from fat oil", None, None), + ("report_new_entrant_production", "report new entrant production", None, None), + ] diff --git a/bc_obps/reporting/tests/models/test_report_new_entrant_production.py b/bc_obps/reporting/tests/models/test_report_new_entrant_production.py new file mode 100644 index 0000000000..ec26e5c945 --- /dev/null +++ b/bc_obps/reporting/tests/models/test_report_new_entrant_production.py @@ -0,0 +1,16 @@ +from common.tests.utils.helpers import BaseTestCase +from reporting.tests.utils.report_data_bakers import report_new_entrant_production_baker +from registration.tests.constants import TIMESTAMP_COMMON_FIELDS + + +class ReportNewEntrantProductionModelTest(BaseTestCase): + @classmethod + def setUpTestData(cls): + cls.test_object = report_new_entrant_production_baker() + cls.field_data = [ + *TIMESTAMP_COMMON_FIELDS, + ("id", "ID", None, None), + ("product", "product", None, None), + ("report_new_entrant", "report new entrant", None, None), + ("production_amount", "production amount", None, None), + ] diff --git a/bc_obps/reporting/tests/models/test_report_version.py b/bc_obps/reporting/tests/models/test_report_version.py index d46e14f0e2..14680f7bfe 100644 --- a/bc_obps/reporting/tests/models/test_report_version.py +++ b/bc_obps/reporting/tests/models/test_report_version.py @@ -25,4 +25,5 @@ def setUpTestData(cls): ("reportsourcetype_records", "report source type", None, 0), ("reportunit_records", "report unit", None, 0), ("report_products", "report product", None, 0), + ("report_new_entrant", "report new entrant", None, None), ] diff --git a/bc_obps/reporting/tests/utils/report_data_bakers.py b/bc_obps/reporting/tests/utils/report_data_bakers.py index 50e21458d6..69a7752856 100644 --- a/bc_obps/reporting/tests/utils/report_data_bakers.py +++ b/bc_obps/reporting/tests/utils/report_data_bakers.py @@ -1,5 +1,8 @@ from model_bakery import baker + +from registration.models import RegulatedProduct from registration.tests.utils.bakers import facility_baker +from reporting.models import ReportNewEntrant, ReportNewEntrantProduction from reporting.models.activity_json_schema import ActivityJsonSchema from reporting.models.activity_source_type_json_schema import ActivitySourceTypeJsonSchema from reporting.models.facility_report import FacilityReport @@ -115,3 +118,25 @@ def report_raw_activity_data_baker(**props): } return baker.make(ReportRawActivityData, **(default_props | props)) + + +def report_new_entrant_baker(**props) -> ReportNewEntrant: + # Check if 'report_version' is provided in props, if not, create a new ReportVersion instance + if "report_version" not in props: + props["report_version"] = report_version_baker() # Assuming the `report_version_baker` function is available + + # Use baker to create a ReportNewEntrant instance with provided or default properties + report = baker.make(ReportNewEntrant, **props) + + return report + + +def report_new_entrant_production_baker(**props): + report_new_entrant = props.get('report_new_entrant') or report_new_entrant_baker() + product = props.get('product') or baker.make(RegulatedProduct) + default_props = { + "product": product, + "report_new_entrant": report_new_entrant, + "production_amount": 500, + } + return baker.make(ReportNewEntrantProduction, **(default_props | props)) diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx index d8d2f28124..00de1e0d24 100644 --- a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformation.tsx @@ -1,20 +1,101 @@ import { Suspense } from "react"; import Loading from "@bciers/components/loading/SkeletonForm"; import NewEntrantInformationForm from "./NewEntrantInformationForm"; -import { getReportProducts } from "@reporting/src/app/utils/getReportProducts"; +import { getNewEntrantData } from "@reporting/src/app/utils/getNewEntrantData"; + +// Define type for Product to ensure consistency +type Product = { + id: string | number; + name: string; +}; export default async function NewEntrantInformation({ versionId, }: { versionId: number; }) { - const reportProducts = await getReportProducts(versionId); + const newEntrantData = await getNewEntrantData(versionId); + + const { + report_new_entrant_data: reportNewEntrantData = {}, + regulated_products: regulatedProducts, + } = newEntrantData || {}; + const initialFormData = reportNewEntrantData; // Already fallback to empty object + const assertionStatement = initialFormData?.assertion_statement; + const emissionAfterNewEntrant = { + flaring_emissions: initialFormData.flaring_emissions || "", + fugitive_emissions: initialFormData.fugitive_emissions || "", + industrial_process_emissions: + initialFormData.industrial_process_emissions || "", + on_site_transportation_emissions: + initialFormData.on_site_transportation_emissions || "", + stationary_fuel_combustion_emissions: + initialFormData.stationary_fuel_combustion_emissions || "", + venting_emissions_useful: initialFormData.venting_emissions_useful || "", + venting_emissions_non_useful: + initialFormData.venting_emissions_non_useful || "", + emissions_from_waste: initialFormData.emissions_from_waste || "", + emissions_from_wastewater: initialFormData.emissions_from_wastewater || "", + }; + + const emissionExcludedByFuelType = { + co2_emissions_from_excluded_woody_biomass: + initialFormData.co2_emissions_from_excluded_woody_biomass || "", + other_emissions_from_excluded_biomass: + initialFormData.other_emissions_from_excluded_biomass || "", + emissions_from_excluded_non_biomass: + initialFormData.emissions_from_excluded_non_biomass || "", + }; + + const otherExcludedEmissions = { + emissions_from_line_tracing: + initialFormData.emissions_from_line_tracing || "", + emissions_from_fat_oil: initialFormData.emissions_from_fat_oil || "", + }; + + // Mapping over the products to transform data + const transformedProducts = regulatedProducts?.map((product: Product) => { + const selectedProduct = initialFormData.selected_products?.find( + (selectedProductObj: { [key: string]: any }) => + selectedProductObj[product.id], + ); + + const productionAmount = + selectedProduct?.[product.id]?.production_amount || ""; + + return { + id: product.id, + name: product.name, + production_amount: productionAmount, + }; + }); + const dateOfAuthorization = initialFormData?.authorization_date || ""; + const dateOfFirstShipment = initialFormData?.first_shipment_date || ""; + const dateOfNewEntrantPeriod = + initialFormData?.new_entrant_period_start || ""; + + // Define initial form values for NewEntrantInformationForm + const initialFormValues = { + assertion_statement: assertionStatement, + emission_after_new_entrant: emissionAfterNewEntrant, + emission_excluded_by_fuel_type: emissionExcludedByFuelType, + other_excluded_emissions: otherExcludedEmissions, + }; return ( }> ); diff --git a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx index 007924bf47..023809b64a 100644 --- a/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx +++ b/bciers/apps/reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm.tsx @@ -10,6 +10,7 @@ import { createNewEntrantInformationSchema, createNewEntrantInformationUiSchema, } from "@reporting/src/data/jsonSchema/newEntrantInformation"; +import { IChangeEvent } from "@rjsf/core"; const baseUrl = "/reports"; const cancelUrl = "/reports"; @@ -17,16 +18,25 @@ const cancelUrl = "/reports"; interface AdditionalReportingDataProps { versionId: number; products: []; + initialFormData: {}; + dateOfAuthorization: string; + dateOfFirstShipment: string; + dateOfNewEntrantPeriod: string; } export default function NewEntrantInformationForm({ versionId, products, + initialFormData, + dateOfAuthorization, + dateOfFirstShipment, + dateOfNewEntrantPeriod, }: AdditionalReportingDataProps) { - const [formData, setFormData] = useState(); + const [formData, setFormData] = useState(initialFormData || {}); + const [submitButtonDisabled, setSubmitButtonDisabled] = useState(true); const router = useRouter(); - const saveAndContinueUrl = `/reports/${versionId}/new-entrant-information`; + const saveAndContinueUrl = `/reports/${versionId}/compliance-summary`; const taskListElements: TaskListElement[] = [ { @@ -43,18 +53,21 @@ export default function NewEntrantInformationForm({ }, ]; - const handleSubmit = async (data: any) => { - const endpoint = `reporting/report-version/${versionId}/additional-data`; + const handleChange = (e: IChangeEvent) => { + const updatedData = { ...e.formData }; + setFormData(updatedData); + if (updatedData.assertion_statement) { + setSubmitButtonDisabled(false); + } else { + setSubmitButtonDisabled(true); + } + }; + const handleSubmit = async () => { + const endpoint = `reporting/report-version/${versionId}/new-entrant-data`; const method = "POST"; - const payload = { - report_version: versionId, - ...data.captured_emissions_section, - ...data.additional_data_section, - }; - const response = await actionHandler(endpoint, method, endpoint, { - body: JSON.stringify(payload), + body: JSON.stringify(formData), }); if (response) { router.push(saveAndContinueUrl); @@ -72,15 +85,19 @@ export default function NewEntrantInformationForm({ "Sign-off & Submit", ]} taskListElements={taskListElements} - schema={createNewEntrantInformationSchema(products)} + schema={createNewEntrantInformationSchema( + products, + dateOfAuthorization, + dateOfFirstShipment, + dateOfNewEntrantPeriod, + )} uiSchema={createNewEntrantInformationUiSchema(products)} formData={formData} baseUrl={baseUrl} cancelUrl={cancelUrl} - onChange={(data: any) => { - setFormData(data.formData); - }} - onSubmit={(data: any) => handleSubmit(data.formData)} + onChange={handleChange} + onSubmit={handleSubmit} + submitButtonDisabled={submitButtonDisabled} /> ); } diff --git a/bciers/apps/reporting/src/app/utils/getNewEntrantData.ts b/bciers/apps/reporting/src/app/utils/getNewEntrantData.ts new file mode 100644 index 0000000000..9e3f0605c7 --- /dev/null +++ b/bciers/apps/reporting/src/app/utils/getNewEntrantData.ts @@ -0,0 +1,13 @@ +import { actionHandler } from "@bciers/actions"; + +export async function getNewEntrantData(version_id: number) { + let response = await actionHandler( + `reporting/report-version/${version_id}/new-entrant-data`, + "GET", + `reporting/report-version/${version_id}/new-entrant-data`, + ); + + if (response && !response.error) { + return response; + } +} diff --git a/bciers/apps/reporting/src/app/utils/getReportProducts.ts b/bciers/apps/reporting/src/app/utils/getReportProducts.ts deleted file mode 100644 index d45b01e78d..0000000000 --- a/bciers/apps/reporting/src/app/utils/getReportProducts.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { actionHandler } from "@bciers/actions"; -export async function getReportProducts(version_id: number) { - let response = await actionHandler( - `reporting/report-version/${version_id}/regulated-products`, - "GET", - `reporting/report-version/${version_id}/regulated-products`, - ); - - if (response && !response.error) { - return response; - } -} diff --git a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx index 9c5d0d786b..e985298600 100644 --- a/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx +++ b/bciers/apps/reporting/src/data/jsonSchema/newEntrantInformation.tsx @@ -10,14 +10,20 @@ import checkboxWidget from "@bciers/components/form/widgets/CheckboxWidget"; import { BC_GOV_BACKGROUND_COLOR_BLUE } from "@bciers/styles"; import { Typography } from "@mui/material"; -const ProductionDataTitleWidget: React.FC = ({ id, value }) => { +export const ProductionDataTitleWidget: React.FC> = ({ + id, + value, + children, +}) => { return (
- Product: {value} +

+ Product: {value} +

+ {children}
); }; - export const newEntrantInfo = ( <> ({ type: "object", @@ -47,38 +57,45 @@ export const createNewEntrantInformationSchema = ( date_of_authorization: { type: "string", title: "Date of authorization", + default: `${dateOfAuthorization}`, }, date_of_first_shipment: { type: "string", title: "Date of first shipment", + default: `${dateOfFirstShipment}`, }, date_of_new_entrant_period_began: { type: "string", title: "Date new entrant period began", + default: `${dateOfNewEntrantPeriod}`, }, assertion_statement: { type: "boolean", - title: - "I certify that this operation was a reporting operation on the date that the application for designation as a new entrant was submitted to the Director under GGIRCA.", + title: "Assertion statement", default: false, }, - ...selectedProducts.reduce( - (acc, product) => ({ - ...acc, - [`product_${product.id}`]: { - type: "object", - title: `Product: ${product.name}`, - properties: { - production_after_new_entrant: { - type: "number", - title: "Production after new entrant period began", + products: { + type: "object", + properties: { + ...selectedProducts?.reduce( + (acc, product) => ({ + ...acc, + [`${product.id}`]: { + type: "object", + title: `Product: ${product.name}`, + properties: { + production_amount: { + type: "number", + title: "Production after new entrant period began", + default: product.production_amount, + }, + }, }, - }, - }, - }), - {}, - ), - + }), + {}, + ), + }, + }, emission_after_new_entrant: { type: "object", title: "Emission categories after new entrant period began", @@ -129,7 +146,7 @@ export const createNewEntrantInformationSchema = ( type: "number", title: "CO2 emissions from excluded woody biomass", }, - other_emissions_from_excluded_biomasss: { + other_emissions_from_excluded_biomass: { type: "number", title: "Other emissions from excluded biomass", }, @@ -171,30 +188,50 @@ export const createNewEntrantInformationUiSchema = ( assertion_statement: { "ui:widget": checkboxWidget, + "ui:options": { + label: + "I certify that this operation was a reporting operation on the date that the application for designation as a new entrant was submitted to the Director under GGIRCA.", + }, }, date_of_authorization: { "ui:widget": DateWidget, + "ui:options": { + simpleDateFormat: true, + }, }, date_of_first_shipment: { "ui:widget": DateWidget, + "ui:options": { + simpleDateFormat: true, + }, }, date_of_new_entrant_period_began: { "ui:widget": DateWidget, + "ui:options": { + simpleDateFormat: true, + }, }, - ...selectedProducts.reduce<{ [key: string]: any }>((acc, product) => { - acc[`product_${product.id}`] = { - "ui:FieldTemplate": SectionFieldTemplate, - "ui:widget": ProductionDataTitleWidget, - production_after_new_entrant: { - "ui:FieldTemplate": InlineFieldTemplate, - }, - }; - return acc; - }, {}), + products: { + "ui:options": { label: false }, + "ui:FieldTemplate": ({ children }) => <>{children}, + ...selectedProducts?.reduce((acc, product) => { + acc[product.id] = { + "ui:FieldTemplate": ({ id, children }) => ( + + {children} + + ), + production_amount: { + "ui:FieldTemplate": InlineFieldTemplate, + }, + }; + return acc; + }, {}), + }, emission_after_new_entrant: { "ui:FieldTemplate": SectionFieldTemplate, @@ -232,7 +269,7 @@ export const createNewEntrantInformationUiSchema = ( co2_emissions_from_excluded_woody_biomass: { "ui:FieldTemplate": InlineFieldTemplate, }, - other_emissions_from_excluded_biomasss: { + other_emissions_from_excluded_biomass: { "ui:FieldTemplate": InlineFieldTemplate, }, emissions_from_excluded_non_biomass: { diff --git a/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx b/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx index 7074ad0354..b3bb46dd99 100644 --- a/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx +++ b/bciers/apps/reporting/src/data/jsonSchema/productionData.tsx @@ -12,7 +12,9 @@ export const ProductionDataTitleWidget: React.FC = ({ }) => { return (
- Product: {value} +

+ Product: {value} +

); }; @@ -61,6 +63,7 @@ export const buildProductionDataSchema = ( product_name: { title: "Name", type: "string", + value: "custom value", }, unit: { title: "Unit", diff --git a/bciers/apps/reporting/src/tests/components/additionalInformation/NewEntrantInformation.test.tsx b/bciers/apps/reporting/src/tests/components/additionalInformation/NewEntrantInformation.test.tsx new file mode 100644 index 0000000000..620c79c0a0 --- /dev/null +++ b/bciers/apps/reporting/src/tests/components/additionalInformation/NewEntrantInformation.test.tsx @@ -0,0 +1,118 @@ +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import { useRouter } from "next/navigation"; +import { actionHandler } from "@bciers/actions"; +import { vi } from "vitest"; +import NewEntrantInformationForm from "@reporting/src/app/components/additionalInformation/newEntrantInformation/NewEntrantInformationForm"; + +vi.mock("next/navigation", () => ({ + useRouter: vi.fn(), +})); + +vi.mock("@bciers/actions", () => ({ + actionHandler: vi.fn(), +})); + +describe("NewEntrantInformationForm Component", () => { + const versionId = 1; + const products = [ + { id: 1, name: "Product A" }, + { id: 2, name: "Product B" }, + ]; + const initialFormData = { assertion_statement: true }; + const dateOfAuthorization = "2024-01-01"; + const dateOfFirstShipment = "2024-06-01"; + const dateOfNewEntrantPeriod = "2024-12-01"; + const mockPush = vi.fn(); + + beforeEach(() => { + (useRouter as unknown as ReturnType).mockReturnValue({ + push: mockPush, + replace: vi.fn(), + prefetch: vi.fn(), + back: vi.fn(), + }); + + (actionHandler as ReturnType).mockResolvedValue({ + success: true, + }); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it("renders form with initial data", async () => { + render( + , + ); + + const formTitle = await screen.findByText("New entrant information"); + expect(formTitle).toBeInTheDocument(); + }); + + it("disables submit button initially if assertion statement is false", async () => { + render( + , + ); + + const submitButton = screen.getByRole("button", { + name: /Save And Continue/i, + }); + expect(submitButton).toBeDisabled(); + }); + + it("enables submit button when assertion statement is true", async () => { + render( + , + ); + + const submitButton = screen.getByRole("button", { + name: /Save And Continue/i, + }); + expect(submitButton).toBeEnabled(); + }); + + it("submits form data and redirects on success", async () => { + render( + , + ); + + const submitButton = screen.getByRole("button", { + name: /Save And Continue/i, + }); + fireEvent.click(submitButton); + + await waitFor(() => expect(actionHandler).toHaveBeenCalled()); + expect(mockPush).toHaveBeenCalledWith( + `/reports/${versionId}/compliance-summary`, + ); + }); +}); diff --git a/bciers/libs/components/src/form/widgets/CheckboxWidget.tsx b/bciers/libs/components/src/form/widgets/CheckboxWidget.tsx index 2517ad0693..d1acbccf37 100644 --- a/bciers/libs/components/src/form/widgets/CheckboxWidget.tsx +++ b/bciers/libs/components/src/form/widgets/CheckboxWidget.tsx @@ -12,6 +12,7 @@ const CheckboxWidget: React.FC = ({ uiSchema, }) => { const alignment = uiSchema?.["ui:options"]?.alignment || "center"; + const customLabel = uiSchema?.["ui:options"]?.label || label; return ( = ({ }} /> } - label={label} + label={customLabel} style={{ alignItems: alignment === "top" ? "flex-start" : "center", }} diff --git a/bciers/libs/components/src/form/widgets/DateWidget.tsx b/bciers/libs/components/src/form/widgets/DateWidget.tsx index bfce992b18..0627e48e57 100644 --- a/bciers/libs/components/src/form/widgets/DateWidget.tsx +++ b/bciers/libs/components/src/form/widgets/DateWidget.tsx @@ -20,15 +20,16 @@ const DateWidget: React.FC = ({ value, options, }) => { + const simpleDateFormat = options?.simpleDateFormat || false; + const handleChange = (d: Dayjs | null) => { if (!d || !d.isValid()) { return onChange("invalid date"); } - // Set the time to 9am UTC to avoid timezone issues since PST is UTC -8 hours - // This should be enough offset to take eastern timezones into account which have - // less than 8 hours difference eg Atlantic Standard Time is UTC -4 hours - const newDate = dayjs(d).utc().set("hour", 9).toISOString(); + const newDate = simpleDateFormat + ? d.utc().format("YYYY-MM-DD") // Return just the date (no time) + : d.utc().set("hour", 9).toISOString(); // Return full ISO string with time return onChange(newDate); }; @@ -45,10 +46,13 @@ const DateWidget: React.FC = ({ }, }; + // Ensure the value is in the correct format + const formattedValue = value ? dayjs(value).utc().format("YYYY-MM-DD") : null; + return ( Date: Thu, 7 Nov 2024 18:34:59 -0800 Subject: [PATCH 6/6] chore:fixed migration --- ...> 0031_reportnewentrant_reportnewentrantproduction.py} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename bc_obps/reporting/migrations/{0030_reportnewentrant_reportnewentrantproduction.py => 0031_reportnewentrant_reportnewentrantproduction.py} (97%) diff --git a/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py b/bc_obps/reporting/migrations/0031_reportnewentrant_reportnewentrantproduction.py similarity index 97% rename from bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py rename to bc_obps/reporting/migrations/0031_reportnewentrant_reportnewentrantproduction.py index cfc0cd7141..5bbb9ac3ba 100644 --- a/bc_obps/reporting/migrations/0030_reportnewentrant_reportnewentrantproduction.py +++ b/bc_obps/reporting/migrations/0031_reportnewentrant_reportnewentrantproduction.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.9 on 2024-11-07 17:14 +# Generated by Django 5.0.9 on 2024-11-08 02:33 import django.db.models.deletion from django.db import migrations, models @@ -7,8 +7,8 @@ class Migration(migrations.Migration): dependencies = [ - ('registration', '0051_bcgreenhousegasid_historicalbcgreenhousegasid'), - ('reporting', '0029_remove_facilityreport_products_reportproduct_and_more'), + ('registration', '0054_V1_13_0'), + ('reporting', '0030_report_non_attributable_emissions'), ] operations = [ @@ -22,7 +22,7 @@ class Migration(migrations.Migration): 'report_version', models.OneToOneField( db_comment='The associated report version for this new entrant record', - on_delete=django.db.models.deletion.PROTECT, + on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='report_new_entrant', serialize=False,