diff --git a/bc_obps/registration/enums/enums.py b/bc_obps/registration/enums/enums.py
index da9644f7c0..940aea16ba 100644
--- a/bc_obps/registration/enums/enums.py
+++ b/bc_obps/registration/enums/enums.py
@@ -28,3 +28,4 @@ class AccessRequestTypes(Enum):
class OperationTypes(Enum):
LFO = "Linear Facility Operation"
SFO = "Single Facility Operation"
+ EIO = "Electricity Import Operation"
diff --git a/bc_obps/registration/fixtures/mock/facility.json b/bc_obps/registration/fixtures/mock/facility.json
index e1607b72eb..979b203a7e 100644
--- a/bc_obps/registration/fixtures/mock/facility.json
+++ b/bc_obps/registration/fixtures/mock/facility.json
@@ -614,11 +614,8 @@
"operation": "02a3ab84-26c6-4a79-bf89-72f877ceef8e",
"created_by": "00000000-0000-0000-0000-000000000001",
"created_at": "2024-06-05T23:18:07.664Z",
- "name": "Facility 43",
- "type": "Single Facility",
- "swrs_facility_id": 1043,
- "latitude_of_largest_emissions": 43.5,
- "longitude_of_largest_emissions": -123.5
+ "name": "Blight EIO - Draft",
+ "type": "Electricity Import"
}
}
]
diff --git a/bc_obps/registration/fixtures/mock/operation.json b/bc_obps/registration/fixtures/mock/operation.json
index 05f0e7b319..dbc2ff4d97 100644
--- a/bc_obps/registration/fixtures/mock/operation.json
+++ b/bc_obps/registration/fixtures/mock/operation.json
@@ -11,7 +11,6 @@
"swrs_facility_id": 1001,
"status": "Registered",
"bc_obps_regulated_operation": "24-0014",
- "created_at": "2024-2-01T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "Reporting Operation",
"contacts": [1, 2]
@@ -31,7 +30,6 @@
"regulated_products": [1],
"status": "Registered",
"bc_obps_regulated_operation": "24-0015",
- "created_at": "2024-2-02T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "OBPS Regulated Operation",
"contacts": [3, 4]
@@ -49,7 +47,6 @@
"opt_in": false,
"regulated_products": [1],
"status": "Draft",
- "created_at": "2024-2-02T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "OBPS Regulated Operation"
}
@@ -69,7 +66,6 @@
"regulated_products": [2, 6, 7, 8],
"status": "Registered",
"bc_obps_regulated_operation": "23-0001",
- "created_at": "2024-1-31T15:27:00.000Z",
"activities": [1, 3],
"registration_purpose": "OBPS Regulated Operation",
"contacts": [3, 4]
@@ -90,7 +86,6 @@
"regulated_products": [1],
"status": "Registered",
"bc_obps_regulated_operation": "23-0002",
- "created_at": "2024-1-30T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "OBPS Regulated Operation",
"contacts": [1]
@@ -112,7 +107,6 @@
"registration_purpose": "OBPS Regulated Operation",
"status": "Registered",
"bc_obps_regulated_operation": "24-0003",
- "created_at": "2024-1-29T15:27:00.000Z",
"activities": [1, 5],
"operation_has_multiple_operators": true,
"contacts": [3]
@@ -133,7 +127,6 @@
"regulated_products": [1],
"status": "Registered",
"bc_obps_regulated_operation": "24-0004",
- "created_at": "2024-1-28T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "Opted-in Operation",
"contacts": [1]
@@ -153,7 +146,6 @@
"bcghg_id": "23219990006",
"status": "Registered",
"bc_obps_regulated_operation": "24-0005",
- "created_at": "2024-1-27T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "Potential Reporting Operation",
"contacts": [2]
@@ -173,7 +165,6 @@
"bcghg_id": "23219990007",
"status": "Registered",
"bc_obps_regulated_operation": "24-0006",
- "created_at": "2024-1-26T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "Electricity Import Operation",
"contacts": [1]
@@ -194,7 +185,6 @@
"regulated_products": [2],
"status": "Registered",
"bc_obps_regulated_operation": "24-0007",
- "created_at": "2024-1-25T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "New Entrant Operation",
"contacts": [1]
@@ -213,7 +203,6 @@
"opt_in": false,
"status": "Registered",
"bc_obps_regulated_operation": "24-0008",
- "created_at": "2024-1-24T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "Reporting Operation",
"contacts": [2]
@@ -234,7 +223,6 @@
"regulated_products": [3],
"status": "Registered",
"bc_obps_regulated_operation": "24-0009",
- "created_at": "2024-1-23T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "OBPS Regulated Operation",
"contacts": [1, 2]
@@ -254,7 +242,6 @@
"bcghg_id": "23219990011",
"status": "Registered",
"bc_obps_regulated_operation": "24-0010",
- "created_at": "2024-1-22T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "Reporting Operation",
"contacts": [1, 2]
@@ -274,7 +261,6 @@
"regulated_products": [3, 4],
"status": "Registered",
"bc_obps_regulated_operation": "24-0011",
- "created_at": "2024-1-21T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "OBPS Regulated Operation",
"contacts": [1]
@@ -292,7 +278,6 @@
"naics_code": 21,
"opt_in": false,
"bcghg_id": "23219990013",
- "created_at": "2024-1-20T15:27:00.000Z",
"status": "Not Started",
"registration_purpose": "Electricity Import Operation"
}
@@ -311,7 +296,6 @@
"bcghg_id": "23219990014",
"regulated_products": [3],
"status": "Not Started",
- "created_at": "2024-1-19T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "OBPS Regulated Operation"
}
@@ -329,7 +313,6 @@
"opt_in": false,
"bcghg_id": "23219990015",
"status": "Draft",
- "created_at": "2024-1-18T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "Potential Reporting Operation"
}
@@ -349,7 +332,6 @@
"regulated_products": [5],
"status": "Registered",
"bc_obps_regulated_operation": "24-0012",
- "created_at": "2024-1-17T15:27:00.000Z",
"activities": [1, 5],
"registration_purpose": "OBPS Regulated Operation",
"contacts": [3]
@@ -368,7 +350,6 @@
"opt_in": false,
"bcghg_id": "23219990017",
"status": "Draft",
- "created_at": "2024-1-16T15:27:00.000Z",
"activities": [1, 5]
}
},
@@ -388,7 +369,6 @@
"status": "Registered",
"bc_obps_regulated_operation": "24-0013",
"registration_purpose": "New Entrant Operation",
- "created_at": "2024-1-15T15:27:00.000Z",
"activities": [1, 3],
"contacts": [4]
}
@@ -407,7 +387,6 @@
"bcghg_id": "23219990019",
"status": "Registered",
"bc_obps_regulated_operation": "24-0016",
- "created_at": "2024-1-14T15:27:00.000Z",
"registration_purpose": "Reporting Operation",
"activities": [1, 5],
"contacts": [3]
@@ -426,7 +405,6 @@
"bcghg_id": "23219990020",
"status": "Registered",
"bc_obps_regulated_operation": "24-0017",
- "created_at": "2024-1-13T15:27:00.000Z",
"registration_purpose": "Reporting Operation",
"activities": [1, 5],
"contacts": [3]
@@ -445,7 +423,6 @@
"bcghg_id": "23219990021",
"status": "Registered",
"bc_obps_regulated_operation": "24-0018",
- "created_at": "2024-1-12T15:27:00.000Z",
"registration_purpose": "Reporting Operation",
"activities": [1, 5],
"contacts": [4]
@@ -457,13 +434,9 @@
"fields": {
"point_of_contact": 1,
"operator": "4242ea9d-b917-4129-93c2-db00b7451051",
- "name": "Blight SFO - Draft",
- "type": "Single Facility Operation",
- "naics_code": 21,
- "opt_in": false,
- "status": "Draft",
- "created_at": "2024-1-11T15:27:00.000Z",
- "activities": [1, 5]
+ "name": "Blight EIO - Draft",
+ "type": "Electricity Import Operation",
+ "status": "Draft"
}
},
{
@@ -477,7 +450,6 @@
"naics_code": 21,
"opt_in": false,
"status": "Draft",
- "created_at": "2024-1-10T15:27:00.000Z",
"activities": [1, 3]
}
},
diff --git a/bc_obps/registration/migrations/0076_alter_facility_type_alter_historicalfacility_type_and_more.py b/bc_obps/registration/migrations/0076_alter_facility_type_alter_historicalfacility_type_and_more.py
new file mode 100644
index 0000000000..b6f420e2b7
--- /dev/null
+++ b/bc_obps/registration/migrations/0076_alter_facility_type_alter_historicalfacility_type_and_more.py
@@ -0,0 +1,56 @@
+# Generated by Django 5.0.11 on 2025-02-06 19:28
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('registration', '0075_facility_operation_historicalfacility_operation'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='facility',
+ name='type',
+ field=models.CharField(
+ choices=[
+ ('Single Facility', 'Single Facility'),
+ ('Large Facility', 'Large Facility'),
+ ('Medium Facility', 'Medium Facility'),
+ ('Small Aggregate', 'Small Aggregate'),
+ ('Electricity Import', 'Electricity Import'),
+ ],
+ db_comment='The type of the facility',
+ max_length=100,
+ ),
+ ),
+ migrations.AlterField(
+ model_name='historicalfacility',
+ name='type',
+ field=models.CharField(
+ choices=[
+ ('Single Facility', 'Single Facility'),
+ ('Large Facility', 'Large Facility'),
+ ('Medium Facility', 'Medium Facility'),
+ ('Small Aggregate', 'Small Aggregate'),
+ ('Electricity Import', 'Electricity Import'),
+ ],
+ db_comment='The type of the facility',
+ max_length=100,
+ ),
+ ),
+ migrations.AlterField(
+ model_name='operation',
+ name='naics_code',
+ field=models.ForeignKey(
+ blank=True,
+ db_comment="This column refers to an operation's primary NAICS code.",
+ null=True,
+ on_delete=django.db.models.deletion.PROTECT,
+ related_name='operations',
+ to='registration.naicscode',
+ ),
+ ),
+ ]
diff --git a/bc_obps/registration/models/facility.py b/bc_obps/registration/models/facility.py
index 323fe542eb..8b0b64ac88 100644
--- a/bc_obps/registration/models/facility.py
+++ b/bc_obps/registration/models/facility.py
@@ -14,6 +14,7 @@ class Types(models.TextChoices):
LARGE_FACILITY = "Large Facility"
MEDIUM_FACILITY = "Medium Facility"
SMALL_AGGREGATE = "Small Aggregate"
+ ELECTRICITY_IMPORT = "Electricity Import"
id = models.UUIDField(
primary_key=True, default=uuid.uuid4, db_comment="Primary key to identify the facility", verbose_name="ID"
diff --git a/bc_obps/registration/models/operation.py b/bc_obps/registration/models/operation.py
index 1198688bd8..778ca2f056 100644
--- a/bc_obps/registration/models/operation.py
+++ b/bc_obps/registration/models/operation.py
@@ -65,6 +65,7 @@ class DateOfFirstShipmentChoices(models.TextChoices):
NaicsCode,
on_delete=models.PROTECT,
null=True,
+ blank=True,
db_comment="This column refers to an operation's primary NAICS code.",
related_name='operations',
)
diff --git a/bc_obps/registration/schema/v2/operation.py b/bc_obps/registration/schema/v2/operation.py
index 1025b50238..58cf2b6a09 100644
--- a/bc_obps/registration/schema/v2/operation.py
+++ b/bc_obps/registration/schema/v2/operation.py
@@ -77,9 +77,10 @@ class Meta:
class OperationInformationIn(ModelSchema):
+ name: str
registration_purpose: Optional[Operation.Purposes] = None
regulated_products: Optional[List[int]] = None
- activities: List[int]
+ activities: Optional[List[int]] = None
boundary_map: Optional[str] = None
process_flow_diagram: Optional[str] = None
naics_code_id: Optional[int] = None
diff --git a/bc_obps/registration/tests/integration/test_operation_registration.py b/bc_obps/registration/tests/integration/test_operation_registration.py
index 582885af94..2aac38d391 100644
--- a/bc_obps/registration/tests/integration/test_operation_registration.py
+++ b/bc_obps/registration/tests/integration/test_operation_registration.py
@@ -182,7 +182,8 @@ def test_operation_registration_workflow(self, operation_type, purpose):
#### Operation Information Form ####
self._set_operation_information(purpose, operation_type)
#### Facility From ####
- self._set_facilities()
+ if purpose != Operation.Purposes.ELECTRICITY_IMPORT_OPERATION:
+ self._set_facilities()
if purpose == Operation.Purposes.NEW_ENTRANT_OPERATION:
#### New Entrant Application Form ####
diff --git a/bc_obps/service/facility_service.py b/bc_obps/service/facility_service.py
index b375a0dc01..24b759ea7a 100644
--- a/bc_obps/service/facility_service.py
+++ b/bc_obps/service/facility_service.py
@@ -162,10 +162,11 @@ def create_facility_with_designated_operation(cls, user_guid: UUID, payload: Fac
operation = OperationDataAccessService.get_by_id(payload.operation_id)
cls.check_user_access(user_guid, operation)
- # Validate that SFO can only make one facility
- num_facilities = FacilityDataAccessService.get_current_facilities_by_operation(operation).count()
- if num_facilities > 0 and operation.type == OperationTypes.SFO.value:
- raise RuntimeError("SFO can only create one facility, this page should not be accessible")
+ # Validate that SFO and EIO can only have one facility
+ if operation.facilities.count() > 0 and operation.type != OperationTypes.LFO.value:
+ raise Exception(
+ "This type of operation (SFO or EIO) can only have one facility, this page should not be accessible"
+ )
facility_data = cls.prepare_facility_data(payload)
address_data = cls.build_address(payload)
diff --git a/bc_obps/service/operation_service_v2.py b/bc_obps/service/operation_service_v2.py
index b16545f5c1..2346947dd8 100644
--- a/bc_obps/service/operation_service_v2.py
+++ b/bc_obps/service/operation_service_v2.py
@@ -1,5 +1,7 @@
from typing import Optional, Tuple, Callable, Generator, Union
from django.db.models import QuerySet
+from registration.models.facility import Facility
+from registration.schema.v1.facility import FacilityIn
from registration.schema.v2.operation_timeline import OperationTimelineFilterSchema
from service.contact_service_v2 import ContactServiceV2
from service.data_access_service.operation_designated_operator_timeline_service import (
@@ -28,6 +30,7 @@
from registration.models.opted_in_operation_detail import OptedInOperationDetail
from service.data_access_service.opted_in_operation_detail_service import OptedInOperationDataAccessService
from service.document_service_v2 import DocumentServiceV2
+from service.facility_service import FacilityService
from service.operation_service import OperationService
from registration.schema.v2.operation import (
OperationInformationIn,
@@ -320,6 +323,18 @@ def register_operation_information(
if operation.registration_purpose == Operation.Purposes.OPTED_IN_OPERATION:
operation = cls.create_opted_in_operation_detail(user_guid, operation.id)
+ if operation.registration_purpose == Operation.Purposes.ELECTRICITY_IMPORT_OPERATION:
+ # EIO operations have a facility with the same data as the operation
+ eio_payload = FacilityIn(
+ name=payload.name, type=Facility.Types.ELECTRICITY_IMPORT, operation_id=operation.id
+ )
+ facility = operation.facilities.first()
+
+ if not facility:
+ FacilityService.create_facilities_with_designated_operations(user_guid, [eio_payload])
+ else:
+ FacilityService.update_facility(user_guid, facility.id, eio_payload)
+
if operation.status == Operation.Statuses.NOT_STARTED:
cls.update_status(user_guid, operation.id, Operation.Statuses.DRAFT)
return operation
diff --git a/bc_obps/service/tests/test_facility_service.py b/bc_obps/service/tests/test_facility_service.py
index 390438b909..a4a0c61d7b 100644
--- a/bc_obps/service/tests/test_facility_service.py
+++ b/bc_obps/service/tests/test_facility_service.py
@@ -1,3 +1,4 @@
+import re
import pytest
from model_bakery import baker
from registration.schema.v1.facility import FacilityIn
@@ -92,20 +93,14 @@ def test_create_facilities_with_designated_operations_create_single_facility():
@staticmethod
def test_create_facilities_with_designated_operations_create_multiple_facilities():
- user = baker.make(User, app_role=AppRole.objects.get(role_name="industry_user"))
- operator = operator_baker()
- baker.make(
- UserOperator,
- user_id=user.user_guid,
- status=UserOperator.Statuses.APPROVED,
- operator=operator,
- role=UserOperator.Roles.ADMIN,
+ approved_user_operator = baker.make_recipe('utils.approved_user_operator')
+ owning_operation: Operation = baker.make_recipe(
+ 'utils.operation', operator=approved_user_operator.operator, type="Linear Facility Operation"
)
- owning_operation: Operation = operation_baker(operator.id)
payload = [
FacilityIn(
name='Test Facility 1',
- type='Single Facility',
+ type='Medium Facility',
latitude_of_largest_emissions=5,
longitude_of_largest_emissions=5,
operation_id=owning_operation.id,
@@ -116,7 +111,7 @@ def test_create_facilities_with_designated_operations_create_multiple_facilities
province='AB',
postal_code='H0H0H0',
name='Test Facility 2',
- type='Large Facility',
+ type='Medium Facility',
latitude_of_largest_emissions=5,
longitude_of_largest_emissions=5,
operation_id=owning_operation.id,
@@ -131,7 +126,7 @@ def test_create_facilities_with_designated_operations_create_multiple_facilities
),
]
- FacilityService.create_facilities_with_designated_operations(user.user_guid, payload)
+ FacilityService.create_facilities_with_designated_operations(approved_user_operator.user.user_guid, payload)
assert len(Facility.objects.all()) == 3
@@ -185,7 +180,12 @@ def test_create_second_sfo_facility_error():
assert Facility.objects.get(name="doraemon") is not None
# test if second facility raises proper exception
- with pytest.raises(RuntimeError, match='SFO can only create one facility, this page should not be accessible'):
+ with pytest.raises(
+ Exception,
+ match=re.escape(
+ "This type of operation (SFO or EIO) can only have one facility, this page should not be accessible"
+ ),
+ ):
FacilityService.create_facility_with_designated_operation(approved_user_operator.user.user_guid, payload2)
@staticmethod
diff --git a/bc_obps/service/tests/test_operation_service_v2.py b/bc_obps/service/tests/test_operation_service_v2.py
index 7f7a1d7469..b40d914f45 100644
--- a/bc_obps/service/tests/test_operation_service_v2.py
+++ b/bc_obps/service/tests/test_operation_service_v2.py
@@ -3,6 +3,7 @@
import pytest
from uuid import uuid4
from zoneinfo import ZoneInfo
+from registration.models.facility import Facility
from registration.schema.v2.operation_timeline import OperationTimelineFilterSchema
from registration.models.contact import Contact
@@ -356,12 +357,66 @@ def test_create_or_replace_new_entrant_application():
assert operation.date_of_first_shipment == Operation.DateOfFirstShipmentChoices.ON_OR_BEFORE_MARCH_31_2024
assert operation.documents.filter(type=DocumentType.objects.get(name='new_entrant_application')).count() == 1
+
+class TestRegisterOperationInformation:
@staticmethod
- def test_register_operation_information_new_operation():
+ def test_register_operation_information_new_eio():
approved_user_operator = baker.make_recipe('registration.tests.utils.approved_user_operator')
+ payload = OperationInformationIn(
+ registration_purpose='Electricity Import Operation',
+ name="TestEIO",
+ type="Electricity Import Operation",
+ )
+ # check operation
+ operation = OperationServiceV2.register_operation_information(
+ approved_user_operator.user.user_guid, None, payload
+ )
+ operation.refresh_from_db()
+ assert Operation.objects.count() == 1
+ # check purpose and status
+ assert operation.registration_purpose == Operation.Purposes.ELECTRICITY_IMPORT_OPERATION
+ assert operation.status == Operation.Statuses.DRAFT
+ # check facility
+ facilities = operation.facilities.all()
+ assert facilities.count() == 1
+ assert facilities[0].name == "TestEIO"
+ assert facilities[0].type == Facility.Types.ELECTRICITY_IMPORT
+ @staticmethod
+ def test_register_operation_information_existing_eio():
+ approved_user_operator = baker.make_recipe('utils.approved_user_operator')
+ users_operation = baker.make_recipe(
+ 'utils.operation',
+ operator=approved_user_operator.operator,
+ created_by=approved_user_operator.user,
+ type="Electricity Import Operation",
+ )
payload = OperationInformationIn(
registration_purpose='Electricity Import Operation',
+ name="UpdatedEIO",
+ type="Electricity Import Operation",
+ )
+ # check operation updates
+ operation = OperationServiceV2.register_operation_information(
+ approved_user_operator.user.user_guid, users_operation.id, payload
+ )
+ operation.refresh_from_db()
+ assert Operation.objects.count() == 1
+ # check purpose and status
+ assert operation.registration_purpose == Operation.Purposes.ELECTRICITY_IMPORT_OPERATION
+ assert operation.status == Operation.Statuses.DRAFT
+ # check facility
+ facilities = operation.facilities.all()
+ assert facilities.count() == 1
+ assert facilities[0].name == "UpdatedEIO"
+ assert facilities[0].type == Facility.Types.ELECTRICITY_IMPORT
+
+ @staticmethod
+ def test_register_operation_information_new_operation():
+ approved_user_operator = baker.make_recipe('registration.tests.utils.approved_user_operator')
+
+ payload = OperationInformationIn(
+ registration_purpose='Reporting Operation',
name="string",
type="SFO",
naics_code_id=1,
@@ -378,8 +433,10 @@ def test_register_operation_information_new_operation():
assert operation.created_at is not None
assert operation.updated_by is not None # the operation is created first, and then we add the purpose
# check purpose
- assert operation.registration_purpose == Operation.Purposes.ELECTRICITY_IMPORT_OPERATION
+ assert operation.registration_purpose == Operation.Purposes.REPORTING_OPERATION
assert operation.status == Operation.Statuses.DRAFT
+ facilities = operation.facilities.all()
+ assert facilities.count() == 0
@staticmethod
def test_register_operation_information_existing_operation():
@@ -408,6 +465,8 @@ def test_register_operation_information_existing_operation():
# check purpose
assert operation.registration_purpose == Operation.Purposes.POTENTIAL_REPORTING_OPERATION
assert operation.status == Operation.Statuses.DRAFT
+ facilities = operation.facilities.all()
+ assert facilities.count() == 0
@staticmethod
def test_is_operation_new_entrant_information_complete_true():
diff --git a/bciers/apps/administration/app/components/operations/cells/OperationFacilitiesActionCell.tsx b/bciers/apps/administration/app/components/operations/cells/OperationFacilitiesActionCell.tsx
index 92df1c3a62..ca2de1c612 100644
--- a/bciers/apps/administration/app/components/operations/cells/OperationFacilitiesActionCell.tsx
+++ b/bciers/apps/administration/app/components/operations/cells/OperationFacilitiesActionCell.tsx
@@ -4,7 +4,10 @@ import { OperationTypes } from "@bciers/utils/src/enums";
const OperationFacilitiesActionCell = (isInternalUser: boolean) => {
const renderCell = (params: GridRenderCellParams) => {
- const operationType = params.row.operation__type;
+ const operationType = params.row.operation__type as OperationTypes;
+
+ if (operationType === OperationTypes.EIO) return N/A;
+
const isSfo = operationType === OperationTypes.SFO;
const sfoFacilityId = params.row.sfo_facility_id;
diff --git a/bciers/apps/administration/app/data/jsonSchema/operationInformation/administrationOperationInformation.ts b/bciers/apps/administration/app/data/jsonSchema/operationInformation/administrationOperationInformation.ts
index a005f49513..a459ea0d91 100644
--- a/bciers/apps/administration/app/data/jsonSchema/operationInformation/administrationOperationInformation.ts
+++ b/bciers/apps/administration/app/data/jsonSchema/operationInformation/administrationOperationInformation.ts
@@ -15,14 +15,18 @@ import {
import { Apps, OperationStatus } from "@bciers/utils/src/enums";
import { optedInOperationDetailsUiSchema } from "./optedInOperation";
+import { RegistrationPurposes } from "@/registration/app/components/operations/registration/enums";
export const createAdministrationOperationInformationSchema = async (
- registrationPurposeValue: string,
+ registrationPurposeValue: RegistrationPurposes,
status: OperationStatus,
): Promise => {
const administrationOperationInformationSchema: RJSFSchema = {
type: "object",
properties: {
- section1: await createOperationInformationSchema(Apps.ADMINISTRATION),
+ section1: await createOperationInformationSchema(
+ Apps.ADMINISTRATION,
+ registrationPurposeValue,
+ ),
section2: await createMultipleOperatorsInformationSchema(),
...(status === OperationStatus.REGISTERED && {
section3: await createAdministrationRegistrationInformationSchema(
diff --git a/bciers/apps/administration/app/data/jsonSchema/operationInformation/operationInformation.ts b/bciers/apps/administration/app/data/jsonSchema/operationInformation/operationInformation.ts
index 6fb5bfe595..45d7c8ca58 100644
--- a/bciers/apps/administration/app/data/jsonSchema/operationInformation/operationInformation.ts
+++ b/bciers/apps/administration/app/data/jsonSchema/operationInformation/operationInformation.ts
@@ -1,121 +1,135 @@
import SectionFieldTemplate from "@bciers/components/form/fields/SectionFieldTemplate";
import { RJSFSchema, UiSchema } from "@rjsf/utils";
import { getNaicsCodes, getReportingActivities } from "@bciers/actions/api";
-import { Apps } from "@bciers/utils/src/enums";
+import { Apps, OperationTypes } from "@bciers/utils/src/enums";
+import { RegistrationPurposes } from "@/registration/app/components/operations/registration/enums";
+
+export const eioOperationInformationSchema: RJSFSchema = {
+ title: "Operation Information",
+ type: "object",
+ required: ["name", "type"],
+ properties: {
+ name: { type: "string", title: "Operation Name" },
+ type: {
+ type: "string",
+ title: "Operation Type",
+ enum: [OperationTypes.EIO],
+ default: OperationTypes.EIO,
+ },
+ },
+};
export const createOperationInformationSchema = async (
app: Apps,
+ registrationPurpose: RegistrationPurposes | undefined,
): Promise => {
+ if (
+ registrationPurpose === RegistrationPurposes.ELECTRICITY_IMPORT_OPERATION
+ ) {
+ return eioOperationInformationSchema;
+ }
+
+ // SFOs and LFOs require more properties and a different type enum
const naicsCodes = await getNaicsCodes();
const reportingActivities = await getReportingActivities();
- const operationInformationSchema: RJSFSchema = {
- title: "Operation Information",
- type: "object",
- required: [
- "name",
- "type",
- "naics_code_id",
- "activities",
- "boundary_map",
- "process_flow_diagram",
- ],
- properties: {
- name: { type: "string", title: "Operation Name" },
- type: {
- type: "string",
- title: "Operation Type",
- enum: ["Single Facility Operation", "Linear Facility Operation"],
- },
- naics_code_id: {
- type: "number",
- title: "Primary NAICS Code",
- anyOf: naicsCodes.map(
- (code: {
- id: number;
- naics_code: string;
- naics_description: string;
- }) => ({
- const: code?.id,
- title: `${code?.naics_code} - ${code?.naics_description}`,
- }),
- ),
- },
- secondary_naics_code_id: {
+ const sfoAndLfoSchema = { ...eioOperationInformationSchema };
+
+ sfoAndLfoSchema.required = [
+ ...(sfoAndLfoSchema.required ?? []),
+ "naics_code_id",
+ "activities",
+ "boundary_map",
+ "process_flow_diagram",
+ ];
+ sfoAndLfoSchema.properties = {
+ ...sfoAndLfoSchema.properties,
+ type: {
+ type: "string",
+ title: "Operation Type",
+ enum: [OperationTypes.SFO, OperationTypes.LFO],
+ },
+ naics_code_id: {
+ type: "number",
+ title: "Primary NAICS Code",
+ anyOf: naicsCodes.map(
+ (code: {
+ id: number;
+ naics_code: string;
+ naics_description: string;
+ }) => ({
+ const: code?.id,
+ title: `${code?.naics_code} - ${code?.naics_description}`,
+ }),
+ ),
+ },
+ secondary_naics_code_id: {
+ type: "number",
+ title: "Secondary NAICS Code",
+ anyOf: naicsCodes.map(
+ (code: {
+ id: number;
+ naics_code: string;
+ naics_description: string;
+ }) => ({
+ const: code?.id,
+ title: `${code?.naics_code} - ${code?.naics_description}`,
+ }),
+ ),
+ },
+ tertiary_naics_code_id: {
+ type: "number",
+ title: "Tertiary NAICS Code",
+ anyOf: naicsCodes.map(
+ (code: {
+ id: number;
+ naics_code: string;
+ naics_description: string;
+ }) => ({
+ const: code?.id,
+ title: `${code?.naics_code} - ${code?.naics_description}`,
+ }),
+ ),
+ },
+
+ activities: {
+ type: "array",
+ minItems: 1,
+ items: {
type: "number",
- title: "Secondary NAICS Code",
- anyOf: naicsCodes.map(
- (code: {
- id: number;
- naics_code: string;
- naics_description: string;
- }) => ({
- const: code?.id,
- title: `${code?.naics_code} - ${code?.naics_description}`,
- }),
+ enum: reportingActivities.map(
+ (activity: { id: number; applicable_to: string; name: string }) =>
+ activity.id,
),
- },
- tertiary_naics_code_id: {
- type: "number",
- title: "Tertiary NAICS Code",
- anyOf: naicsCodes.map(
- (code: {
- id: number;
- naics_code: string;
- naics_description: string;
- }) => ({
- const: code?.id,
- title: `${code?.naics_code} - ${code?.naics_description}`,
- }),
+ // enumNames is a non-standard field required for the MultiSelectWidget
+ // @ts-ignore
+ enumNames: reportingActivities.map(
+ (activity: { applicable_to: string; name: string }) => activity.name,
),
},
-
- activities: {
- type: "array",
- minItems: 1,
- items: {
- type: "number",
- enum: reportingActivities.map(
- (activity: { id: number; applicable_to: string; name: string }) =>
- activity.id,
- ),
- // enumNames is a non-standard field required for the MultiSelectWidget
- // @ts-ignore
- enumNames: reportingActivities.map(
- (activity: { applicable_to: string; name: string }) =>
- activity.name,
- ),
- },
- title: "Reporting Activities",
- },
- process_flow_diagram: {
+ title: "Reporting Activities",
+ },
+ process_flow_diagram: {
+ type: "string",
+ title: "Process Flow Diagram",
+ format: "data-url",
+ },
+ boundary_map: {
+ type: "string",
+ title: "Boundary Map",
+ format: "data-url",
+ },
+ ...(app === Apps.ADMINISTRATION && {
+ bc_obps_regulated_operation: {
type: "string",
- title: "Process Flow Diagram",
- format: "data-url",
+ title: "BORO ID",
},
- boundary_map: {
+ bcghg_id: {
type: "string",
- title: "Boundary Map",
- format: "data-url",
+ title: "BCGHGID",
},
- ...(app === Apps.ADMINISTRATION
- ? {
- bc_obps_regulated_operation: {
- type: "string",
- title: "BORO ID",
- },
- }
- : {}),
- ...(app === Apps.ADMINISTRATION
- ? {
- bcghg_id: {
- type: "string",
- title: "BCGHGID",
- },
- }
- : {}),
- },
+ }),
};
- return operationInformationSchema;
+ return sfoAndLfoSchema;
};
export const operationInformationUISchema: UiSchema = {
diff --git a/bciers/apps/administration/tests/components/operations/OperationInformationForm.test.tsx b/bciers/apps/administration/tests/components/operations/OperationInformationForm.test.tsx
index 7664089656..96bac630d5 100644
--- a/bciers/apps/administration/tests/components/operations/OperationInformationForm.test.tsx
+++ b/bciers/apps/administration/tests/components/operations/OperationInformationForm.test.tsx
@@ -257,7 +257,7 @@ describe("the OperationInformationForm component", () => {
expect(screen.getByRole("button", { name: "Edit" })).toBeVisible();
});
- it("should render the form with the correct values when formData is provided", async () => {
+ it("should render the form with the correct values for a non-EIO when formData is provided", async () => {
fetchFormEnums();
const createdFormSchema =
await createAdministrationOperationInformationSchema(
@@ -310,6 +310,36 @@ describe("the OperationInformationForm component", () => {
expect(screen.getByText(/Reporting Operation/i)).toBeVisible();
});
+ it("should render the form with the correct form for an EIO when formData is provided", async () => {
+ fetchFormEnums();
+ const createdFormSchema =
+ await createAdministrationOperationInformationSchema(
+ RegistrationPurposes.ELECTRICITY_IMPORT_OPERATION,
+ OperationStatus.REGISTERED,
+ );
+ render(
+ ,
+ );
+ //name
+ expect(screen.getByText(/Operation 3/i)).toBeVisible();
+ // type
+ expect(screen.getByText(/Electricity Import Operation/i)).toBeVisible();
+ // primary naics code
+ expect(screen.queryByText(/naics/i)).not.toBeInTheDocument();
+
+ // registration info & purpose
+ expect(
+ screen.getByText(
+ /The purpose of this registration is to register as a\:/i,
+ ),
+ ).toBeVisible();
+ expect(screen.getByText(/Electricity Import Operation/i)).toBeVisible();
+ });
+
it("should enable editing when the Edit button is clicked", async () => {
render(
{
const router = useRouter();
const [selectedOperation, setSelectedOperation] = useState("");
const [error, setError] = useState(undefined);
-
+ const [schema, setSchema] = useState(initialSchema);
const nestedFormData = rawFormData
? createNestedFormData(rawFormData, schema)
: {};
@@ -127,6 +128,20 @@ const OperationInformationForm = ({
},
},
});
+ if (
+ newSelectedPurpose === RegistrationPurposes.ELECTRICITY_IMPORT_OPERATION
+ ) {
+ // EIOs only require basic information, so if a user selects EIO we remove some of the form fields
+ setSchema({
+ ...initialSchema,
+ properties: {
+ ...initialSchema.properties,
+ section2: eioOperationInformationSchema,
+ },
+ });
+ } else {
+ setSchema(initialSchema);
+ }
setFormState(data);
};
diff --git a/bciers/apps/registration/app/data/jsonSchema/operationInformation/registrationOperationInformation.ts b/bciers/apps/registration/app/data/jsonSchema/operationInformation/registrationOperationInformation.ts
index 1f882a0634..d072332c04 100644
--- a/bciers/apps/registration/app/data/jsonSchema/operationInformation/registrationOperationInformation.ts
+++ b/bciers/apps/registration/app/data/jsonSchema/operationInformation/registrationOperationInformation.ts
@@ -21,7 +21,10 @@ export const createRegistrationOperationInformationSchema =
type: "object",
properties: {
section1: await createRegistrationPurposeSchema(),
- section2: await createOperationInformationSchema(Apps.REGISTRATION),
+ section2: await createOperationInformationSchema(
+ Apps.REGISTRATION,
+ undefined,
+ ),
section3: await createMultipleOperatorsInformationSchema(),
},
};
diff --git a/bciers/apps/registration/tests/components/operations/OperationRegistrationPage.test.tsx b/bciers/apps/registration/tests/components/operations/OperationRegistrationPage.test.tsx
index 5668a5511c..823f957b90 100644
--- a/bciers/apps/registration/tests/components/operations/OperationRegistrationPage.test.tsx
+++ b/bciers/apps/registration/tests/components/operations/OperationRegistrationPage.test.tsx
@@ -146,10 +146,10 @@ describe("the OperationRegistrationPage component", () => {
);
});
- it("should render the Operation Representative Form and 4 steps", async () => {
+ it("should render the Operation Representative Form and 3 steps if the purpose is Electricity Import Operation", async () => {
// purpose
actionHandler.mockResolvedValueOnce({
- registration_purpose: "OBPS Regulated Operation",
+ registration_purpose: "Electricity Import Operation",
});
// contacts
@@ -164,7 +164,7 @@ describe("the OperationRegistrationPage component", () => {
render(
await OperationRegistrationPage({
operation: "002d5a9e-32a6-4191-938c-2c02bfec592d",
- step: 3,
+ step: 2,
searchParams: {},
}),
);
diff --git a/bciers/apps/registration/tests/components/operations/registration/OperationInformationForm.test.tsx b/bciers/apps/registration/tests/components/operations/registration/OperationInformationForm.test.tsx
index c287fb43de..313ae13964 100644
--- a/bciers/apps/registration/tests/components/operations/registration/OperationInformationForm.test.tsx
+++ b/bciers/apps/registration/tests/components/operations/registration/OperationInformationForm.test.tsx
@@ -183,7 +183,7 @@ describe("the OperationInformationForm component", () => {
);
it(
- "should submit a new operation with regulated products and multiple operators",
+ "should submit a new OBPS regulated operation with regulated products and multiple operators",
{
timeout: 60000,
},
@@ -349,6 +349,67 @@ describe("the OperationInformationForm component", () => {
},
);
+ it(
+ "should submit a new EIO operation",
+ {
+ timeout: 60000,
+ },
+ async () => {
+ fetchFormEnums();
+ actionHandler.mockResolvedValueOnce({
+ id: "b974a7fc-ff63-41aa-9d57-509ebe2553a4",
+ name: "EIO Op Name",
+ }); // mock the POST response from the submit handler
+ render(
+ ,
+ );
+
+ const purposeInput = screen.getByRole("combobox", {
+ name: /The purpose of this registration+/i,
+ });
+ await fillComboboxWidgetField(
+ purposeInput,
+ "Electricity Import Operation",
+ );
+
+ await userEvent.type(
+ screen.getByLabelText(/Operation Name/i),
+ "EIO Op Name",
+ );
+
+ // EIO is the default operation type if purpose is EIO so we don't have to fill it in
+
+ // submit
+
+ await userEvent.click(
+ screen.getByRole("button", { name: /save and continue/i }),
+ );
+ await waitFor(() => {
+ expect(actionHandler).toHaveBeenLastCalledWith(
+ "registration/operations",
+ "POST",
+ "",
+ {
+ body: JSON.stringify({
+ registration_purpose: "Electricity Import Operation",
+ name: "EIO Op Name",
+ type: "Electricity Import Operation",
+ operation_has_multiple_operators: false,
+ }),
+ },
+ );
+ });
+ expect(mockPush).toHaveBeenCalledWith(
+ "/register-an-operation/b974a7fc-ff63-41aa-9d57-509ebe2553a4/2?operations_title=EIO%20Op%20Name",
+ );
+ },
+ );
+
it("should show the correct help text when selecting a purpose", async () => {
fetchFormEnums();
render(
diff --git a/bciers/libs/utils/src/enums.ts b/bciers/libs/utils/src/enums.ts
index b0aecf1cc4..406eddb120 100644
--- a/bciers/libs/utils/src/enums.ts
+++ b/bciers/libs/utils/src/enums.ts
@@ -38,11 +38,13 @@ export enum OperationStatus {
export enum OperationTypes {
SFO = "Single Facility Operation",
LFO = "Linear Facility Operation",
+ EIO = "Electricity Import Operation",
}
export enum FacilityTypes {
SFO = "Single Facility",
LFO = "Linear Facility",
+ EIO = "Electricity Import",
}
export enum OperatorStatus {