From a8c272fc899693e7a1637e0ca5ef0d971bb8b4de Mon Sep 17 00:00:00 2001 From: Daniel Haselhan Date: Thu, 5 Dec 2024 11:43:14 -0800 Subject: [PATCH 01/15] fix: Load EER ratio even when end use is not defined --- backend/lcfs/web/api/fuel_code/repo.py | 39 ++++++++++++++++++-------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/backend/lcfs/web/api/fuel_code/repo.py b/backend/lcfs/web/api/fuel_code/repo.py index 7e0d0f534..4cc699008 100644 --- a/backend/lcfs/web/api/fuel_code/repo.py +++ b/backend/lcfs/web/api/fuel_code/repo.py @@ -776,18 +776,35 @@ async def get_provision_of_the_act_by_name( @repo_handler async def get_energy_effectiveness_ratio( - self, fuel_type_id: int, fuel_category_id: int, end_use_type_id: int + self, fuel_type_id: int, fuel_category_id: int, end_use_type_id: Optional[int] ) -> EnergyEffectivenessRatio: + """ + Retrieves the Energy Effectiveness Ratio based on fuel type, fuel category, + and optionally the end use type. + + Args: + fuel_type_id (int): The ID of the fuel type. + fuel_category_id (int): The ID of the fuel category. + end_use_type_id (Optional[int]): The ID of the end use type (optional). - stmt = select(EnergyEffectivenessRatio).where( + Returns: + Optional[EnergyEffectivenessRatio]: The matching EnergyEffectivenessRatio record or None. + """ + conditions = [ EnergyEffectivenessRatio.fuel_type_id == fuel_type_id, EnergyEffectivenessRatio.fuel_category_id == fuel_category_id, - EnergyEffectivenessRatio.end_use_type_id == end_use_type_id, - ) + ] + + if end_use_type_id is not None: + conditions.append( + EnergyEffectivenessRatio.end_use_type_id == end_use_type_id + ) + + stmt = select(EnergyEffectivenessRatio).where(*conditions) result = await self.db.execute(stmt) - energy_density = result.scalars().first() + energy_effectiveness_ratio = result.scalars().first() - return energy_density + return energy_effectiveness_ratio @repo_handler async def get_target_carbon_intensities( @@ -848,12 +865,10 @@ async def get_standardized_fuel_data( effective_carbon_intensity = fuel_type.default_carbon_intensity # Get energy effectiveness ratio (EER) - eer = None - if fuel_type_id and fuel_category_id and end_use_id: - energy_effectiveness = await self.get_energy_effectiveness_ratio( - fuel_type_id, fuel_category_id, end_use_id - ) - eer = energy_effectiveness.ratio if energy_effectiveness else 1.0 + energy_effectiveness = await self.get_energy_effectiveness_ratio( + fuel_type_id, fuel_category_id, end_use_id + ) + eer = energy_effectiveness.ratio if energy_effectiveness else 1.0 # Fetch target carbon intensity (TCI) target_ci = None From d562b138cdef601ecccb864928be7047b042e93c Mon Sep 17 00:00:00 2001 From: Daniel Haselhan Date: Fri, 6 Dec 2024 11:33:17 -0800 Subject: [PATCH 02/15] Add Tests --- .../tests/fuel_code/test_fuel_code_repo.py | 645 +++++++++++++++++- backend/lcfs/web/api/fuel_code/repo.py | 4 +- 2 files changed, 634 insertions(+), 15 deletions(-) diff --git a/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py b/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py index a8c4945d1..91b3d6b09 100644 --- a/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py +++ b/backend/lcfs/tests/fuel_code/test_fuel_code_repo.py @@ -1,13 +1,40 @@ +from datetime import date +from unittest import mock + import pytest from unittest.mock import AsyncMock, MagicMock +from sqlalchemy.exc import NoResultFound +from sqlalchemy.orm import joinedload + from lcfs.web.api.fuel_code.repo import FuelCodeRepository from lcfs.db.models.fuel.TransportMode import TransportMode +from lcfs.db.models.fuel.FuelType import FuelType +from lcfs.db.models.fuel.FuelCategory import FuelCategory +from lcfs.db.models.fuel.UnitOfMeasure import UnitOfMeasure +from lcfs.db.models.fuel.ExpectedUseType import ExpectedUseType +from lcfs.db.models.fuel.FuelCode import FuelCode +from lcfs.db.models.fuel.FuelCodePrefix import FuelCodePrefix +from lcfs.db.models.fuel.FuelCodeStatus import FuelCodeStatus, FuelCodeStatusEnum +from lcfs.db.models.fuel.EnergyDensity import EnergyDensity +from lcfs.db.models.fuel.EnergyEffectivenessRatio import EnergyEffectivenessRatio +from lcfs.db.models.fuel.ProvisionOfTheAct import ProvisionOfTheAct +from lcfs.db.models.fuel.AdditionalCarbonIntensity import AdditionalCarbonIntensity +from lcfs.db.models.fuel.TargetCarbonIntensity import TargetCarbonIntensity +from lcfs.db.models.compliance.CompliancePeriod import CompliancePeriod +from lcfs.web.exception.exceptions import DatabaseException @pytest.fixture def mock_db(): """Fixture for mocking the database session.""" - return AsyncMock() + mock_session = AsyncMock() + mock_session.execute = AsyncMock() + mock_session.get_one = AsyncMock() + mock_session.add = MagicMock() + mock_session.flush = AsyncMock() + mock_session.refresh = AsyncMock() + mock_session.scalar = AsyncMock() + return mock_session @pytest.fixture @@ -18,21 +45,613 @@ def fuel_code_repo(mock_db): return repo +@pytest.fixture +def valid_fuel_code(): + """Fixture for creating a repository with a mocked database.""" + fc = FuelCode( + fuel_code_id=5, + fuel_suffix="105.0", + prefix_id=1, # Assuming prefix_id=1 exists + fuel_type_id=1, # Assuming fuel_type_id=1 exists + company="Test Company", + contact_name="Test Contact", + contact_email="test@example.com", + carbon_intensity=50.00, + edrms="EDRMS-001", + application_date=date.today(), + feedstock="Corn", + feedstock_location="USA", + feedstock_misc="", + fuel_production_facility_city="CityA", + fuel_production_facility_province_state="ProvinceA", + fuel_production_facility_country="CountryA", + last_updated=date.today(), + ) + return fc + + @pytest.mark.anyio -async def test_get_transport_mode_by_name(fuel_code_repo, mock_db): - # Define the test transport mode - transport_mode_name = "Truck" - mock_transport_mode = TransportMode(transport_mode_id=1, transport_mode="Truck") +async def test_get_fuel_types(fuel_code_repo, mock_db): + mock_fuel_type = FuelType(fuel_type_id=1, fuel_type="Diesel") + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [mock_fuel_type] - # Mock the database query result - mock_db.execute.return_value.scalar_one = MagicMock() - mock_db.execute.return_value.scalar_one.return_value = mock_transport_mode + mock_db.execute.return_value = mock_result + result = await fuel_code_repo.get_fuel_types() + assert len(result) == 1 + assert result[0] == mock_fuel_type + mock_db.execute.assert_called_once() - # Call the repository method - result = await fuel_code_repo.get_transport_mode_by_name(transport_mode_name) - # Assert the result matches the mock data - assert result == mock_transport_mode +@pytest.mark.anyio +async def test_get_formatted_fuel_types(fuel_code_repo, mock_db): + # Setup mock data + mock_fuel_type = FuelType( + fuel_type_id=1, + fuel_type="Diesel", + default_carbon_intensity=80.0, + units="gCO2e/MJ", + unrecognized=False, + ) + mock_result = MagicMock() + mock_result.unique.return_value.scalars.return_value.all.return_value = [ + mock_fuel_type + ] + mock_db.execute.return_value = mock_result - # Ensure the database query was called + result = await fuel_code_repo.get_formatted_fuel_types() + assert len(result) == 1 + assert result[0]["fuel_type"] == "Diesel" mock_db.execute.assert_called_once() + + +@pytest.mark.anyio +async def test_get_fuel_type_by_name_found(fuel_code_repo, mock_db): + mock_fuel_type = FuelType(fuel_type_id=2, fuel_type="Gasoline") + mock_result = MagicMock() + mock_result.scalars.return_value.first.return_value = mock_fuel_type + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_fuel_type_by_name("Gasoline") + assert result == mock_fuel_type + + +@pytest.mark.anyio +async def test_get_fuel_type_by_name_not_found(fuel_code_repo, mock_db): + mock_result = MagicMock() + mock_result.scalars.return_value.first.return_value = None + mock_db.execute.return_value = mock_result + + with pytest.raises(DatabaseException): + await fuel_code_repo.get_fuel_type_by_name("Nonexistent") + + +@pytest.mark.anyio +async def test_get_fuel_type_by_id_found(fuel_code_repo, mock_db): + mock_fuel_type = FuelType(fuel_type_id=3, fuel_type="Biofuel") + mock_db.get_one.return_value = mock_fuel_type + + result = await fuel_code_repo.get_fuel_type_by_id(3) + assert result == mock_fuel_type + mock_db.get_one.assert_called_once() + + +@pytest.mark.anyio +async def test_get_fuel_type_by_id_not_found(fuel_code_repo, mock_db): + mock_db.get_one.return_value = None + with pytest.raises(DatabaseException): + await fuel_code_repo.get_fuel_type_by_id(999) + + +@pytest.mark.anyio +async def test_get_fuel_categories(fuel_code_repo, mock_db): + mock_fc = FuelCategory(fuel_category_id=1, category="Renewable") + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [mock_fc] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_fuel_categories() + assert len(result) == 1 + assert result[0] == mock_fc + + +@pytest.mark.anyio +async def test_get_fuel_category_by_name(fuel_code_repo, mock_db): + mock_fc = FuelCategory(fuel_category_id=2, category="Fossil") + mock_result = MagicMock() + mock_result.scalar_one_or_none.return_value = mock_fc + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_fuel_category_by_name("Fossil") + assert result == mock_fc + + +@pytest.mark.anyio +async def test_get_transport_modes(fuel_code_repo, mock_db): + mock_tm = TransportMode(transport_mode_id=1, transport_mode="Truck") + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [mock_tm] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_transport_modes() + assert len(result) == 1 + assert result[0] == mock_tm + + +@pytest.mark.anyio +async def test_get_transport_mode(fuel_code_repo, mock_db): + mock_tm = TransportMode(transport_mode_id=10, transport_mode="Ship") + mock_db.scalar.return_value = mock_tm + + result = await fuel_code_repo.get_transport_mode(10) + assert result == mock_tm + mock_db.scalar.assert_called_once() + + +@pytest.mark.anyio +async def test_get_transport_mode_by_name_found(fuel_code_repo, mock_db): + mock_tm = TransportMode(transport_mode_id=1, transport_mode="Truck") + mock_result = MagicMock() + mock_result.scalar_one.return_value = mock_tm + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_transport_mode_by_name("Truck") + assert result == mock_tm + + +@pytest.mark.anyio +async def test_get_transport_mode_by_name_not_found(fuel_code_repo, mock_db): + mock_result = MagicMock() + mock_result.scalar_one.side_effect = NoResultFound + mock_db.execute.return_value = mock_result + + with pytest.raises(DatabaseException): + await fuel_code_repo.get_transport_mode_by_name("NonexistentMode") + + +@pytest.mark.anyio +async def test_get_fuel_code_prefixes(fuel_code_repo, mock_db): + mock_prefix = FuelCodePrefix(fuel_code_prefix_id=1, prefix="BC") + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [mock_prefix] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_fuel_code_prefixes() + assert len(result) == 1 + assert result[0] == mock_prefix + + +@pytest.mark.anyio +async def test_get_fuel_code_prefix(fuel_code_repo, mock_db): + mock_prefix = FuelCodePrefix(fuel_code_prefix_id=2, prefix="AB") + mock_db.get_one.return_value = mock_prefix + + result = await fuel_code_repo.get_fuel_code_prefix(2) + assert result == mock_prefix + + +@pytest.mark.anyio +async def test_get_fuel_status_by_status(fuel_code_repo, mock_db): + mock_status = FuelCodeStatus( + fuel_code_status_id=1, status=FuelCodeStatusEnum.Approved + ) + mock_result = MagicMock() + mock_result.scalar.return_value = mock_status + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_fuel_status_by_status(FuelCodeStatusEnum.Approved) + assert result == mock_status + + +@pytest.mark.anyio +async def test_get_energy_densities(fuel_code_repo, mock_db): + ed = EnergyDensity(energy_density_id=1, density=35.0) + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [ed] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_energy_densities() + assert len(result) == 1 + assert result[0] == ed + + +@pytest.mark.anyio +async def test_get_energy_density(fuel_code_repo, mock_db): + ed = EnergyDensity(energy_density_id=2, density=40.0) + mock_result = MagicMock() + mock_result.scalars.return_value.first.return_value = ed + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_energy_density(10) + assert result == ed + + +@pytest.mark.anyio +async def test_get_energy_effectiveness_ratios(fuel_code_repo, mock_db): + eer = EnergyEffectivenessRatio(eer_id=1, ratio=2.0) + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [eer] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_energy_effectiveness_ratios() + assert len(result) == 1 + assert result[0] == eer + + +@pytest.mark.anyio +async def test_get_units_of_measure(fuel_code_repo, mock_db): + uom = UnitOfMeasure(uom_id=1, name="gCO2e/MJ") + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [uom] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_units_of_measure() + assert len(result) == 1 + assert result[0] == uom + + +@pytest.mark.anyio +async def test_get_expected_use_types(fuel_code_repo, mock_db): + eut = ExpectedUseType(expected_use_type_id=1, name="Vehicle") + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [eut] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_expected_use_types() + assert len(result) == 1 + assert result[0] == eut + + +@pytest.mark.anyio +async def test_get_expected_use_type_by_name(fuel_code_repo, mock_db): + eut = ExpectedUseType(expected_use_type_id=2, name="Heating") + mock_result = MagicMock() + mock_result.scalar_one_or_none.return_value = eut + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_expected_use_type_by_name("Heating") + assert result == eut + + +@pytest.mark.anyio +async def test_get_fuel_codes_paginated(fuel_code_repo, mock_db): + fc = FuelCode(fuel_code_id=1, fuel_suffix="101.0") + mock_db.execute.side_effect = [ + MagicMock(scalar=MagicMock(return_value=FuelCodeStatus())), + MagicMock(scalar=MagicMock(return_value=1)), + MagicMock( + unique=MagicMock( + return_value=MagicMock( + scalars=MagicMock( + return_value=MagicMock(all=MagicMock(return_value=[fc])) + ) + ) + ) + ), + ] + pagination = MagicMock(page=1, size=10, filters=[], sort_orders=[]) + result, count = await fuel_code_repo.get_fuel_codes_paginated(pagination) + assert len(result) == 1 + assert result[0] == fc + assert count == 1 + + +@pytest.mark.anyio +async def test_get_fuel_code_statuses(fuel_code_repo, mock_db): + fcs = FuelCodeStatus(fuel_code_status_id=1, status=FuelCodeStatusEnum.Approved) + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [fcs] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_fuel_code_statuses() + assert len(result) == 1 + assert result[0] == fcs + + +@pytest.mark.anyio +async def test_create_fuel_code(fuel_code_repo, mock_db, valid_fuel_code): + mock_db.flush = AsyncMock() + mock_db.scalar.return_value = valid_fuel_code + + result = await fuel_code_repo.create_fuel_code(valid_fuel_code) + assert result == valid_fuel_code + mock_db.add.assert_called_once_with(valid_fuel_code) + + +@pytest.mark.anyio +async def test_get_fuel_code(fuel_code_repo, mock_db, valid_fuel_code): + mock_db.scalar.return_value = valid_fuel_code + result = await fuel_code_repo.get_fuel_code(1) + assert result == valid_fuel_code + + +@pytest.mark.anyio +async def test_get_fuel_code_status_enum(fuel_code_repo, mock_db): + fcs = FuelCodeStatus(fuel_code_status_id=2, status=FuelCodeStatusEnum.Deleted) + mock_db.scalar.return_value = fcs + result = await fuel_code_repo.get_fuel_code_status(FuelCodeStatusEnum.Deleted) + assert result == fcs + + +@pytest.mark.anyio +async def test_update_fuel_code(fuel_code_repo, mock_db, valid_fuel_code): + mock_db.flush = AsyncMock() + mock_db.refresh = AsyncMock() + updated = await fuel_code_repo.update_fuel_code(valid_fuel_code) + assert updated.fuel_code_id == 5 + + +@pytest.mark.anyio +async def test_delete_fuel_code(fuel_code_repo, mock_db): + mock_delete_status = FuelCodeStatus( + fuel_code_status_id=3, status=FuelCodeStatusEnum.Deleted + ) + mock_execute_result = MagicMock() + mock_execute_result.scalar.return_value = mock_delete_status + mock_db.execute.return_value = mock_execute_result + + mock_db.flush = AsyncMock() + + await fuel_code_repo.delete_fuel_code(10) + mock_db.execute.assert_awaited() # Check that execute was awaited + + +@pytest.mark.anyio +async def test_get_distinct_company_names(fuel_code_repo, mock_db): + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = ["CompanyA", "CompanyB"] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_distinct_company_names("Com") + assert len(result) == 2 + + +@pytest.mark.anyio +async def test_get_contact_names_by_company(fuel_code_repo, mock_db): + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = ["John Doe", "Jane Doe"] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_contact_names_by_company("CompanyA", "J") + assert len(result) == 2 + + +@pytest.mark.anyio +async def test_get_contact_email_by_company_and_name(fuel_code_repo, mock_db): + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = ["john@example.com"] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_contact_email_by_company_and_name( + "CompanyA", "John Doe", "john@" + ) + assert len(result) == 1 + + +@pytest.mark.anyio +async def test_get_distinct_fuel_codes_by_code(fuel_code_repo, mock_db): + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = ["101.0", "101.1"] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_distinct_fuel_codes_by_code("101", "BC") + assert len(result) == 2 + + +@pytest.mark.anyio +async def test_get_fuel_code_by_code_prefix(fuel_code_repo, mock_db): + fc = FuelCode(fuel_code_id=10, fuel_suffix="200.0") + mock_result = MagicMock() + mock_result.unique.return_value.scalars.return_value.all.return_value = [fc] + mock_db.execute.return_value = mock_result + + # Mock the next available suffix + fuel_code_repo.get_next_available_sub_version_fuel_code_by_prefix = AsyncMock( + return_value="200.1" + ) + + result = await fuel_code_repo.get_fuel_code_by_code_prefix("200.0", "BC") + assert len(result) == 1 + assert result[0].fuel_suffix == "200.1" + + +@pytest.mark.anyio +async def test_validate_fuel_code(fuel_code_repo, mock_db): + # Mock no existing code + mock_result = MagicMock() + mock_result.scalar_one_or_none.return_value = None + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.validate_fuel_code("300.0", 1) + assert result == "300.0" + + # Mock existing code + mock_result.scalar_one_or_none.return_value = FuelCode( + fuel_code_id=5, fuel_suffix="300.0" + ) + mock_db.execute.return_value = mock_result + fuel_code_repo.get_next_available_sub_version_fuel_code_by_prefix = AsyncMock( + return_value="300.1" + ) + result = await fuel_code_repo.validate_fuel_code("300.0", 1) + assert result == "300.1" + + +@pytest.mark.anyio +async def test_get_next_available_fuel_code_by_prefix(fuel_code_repo, mock_db): + mock_execute_result = MagicMock() + mock_execute_result.scalar_one_or_none.return_value = "102.0" + mock_db.execute.return_value = mock_execute_result + + result = await fuel_code_repo.get_next_available_fuel_code_by_prefix("BC") + assert result == "102.0" + + +@pytest.mark.anyio +async def test_get_next_available_sub_version_fuel_code_by_prefix( + fuel_code_repo, mock_db +): + mock_execute_result = MagicMock() + mock_execute_result.scalar_one_or_none.return_value = "200.1" + mock_db.execute.return_value = mock_execute_result + + result = await fuel_code_repo.get_next_available_sub_version_fuel_code_by_prefix( + "200", 1 + ) + assert result == "200.1" + + +@pytest.mark.anyio +async def test_get_latest_fuel_codes(fuel_code_repo, mock_db, valid_fuel_code): + prefix = FuelCodePrefix(fuel_code_prefix_id=1, prefix="BC") + valid_fuel_code.fuel_code_prefix = prefix + + mock_result = MagicMock() + mock_result.unique.return_value.scalars.return_value.all.return_value = [ + valid_fuel_code + ] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_latest_fuel_codes() + assert len(result) == 1 + # The code increments the version, e.g. "BC101.0" -> "BC101.1" + # Assuming suffix "105.0": + assert result[0]["fuel_code"].endswith(".1") + + +@pytest.mark.anyio +async def test_get_fuel_code_field_options(fuel_code_repo, mock_db): + mock_execute_result = MagicMock() + mock_execute_result.all.return_value = [ + ("CompanyA", "Corn", "USA", None, None, "John Doe", "john@example.com") + ] + mock_db.execute.return_value = mock_execute_result + + result = await fuel_code_repo.get_fuel_code_field_options() + assert len(result) == 1 + + +@pytest.mark.anyio +async def test_get_fp_locations(fuel_code_repo, mock_db): + mock_execute_result = MagicMock() + mock_execute_result.all.return_value = [("CityA", "ProvinceA", "CountryA")] + mock_db.execute.return_value = mock_execute_result + + result = await fuel_code_repo.get_fp_locations() + assert len(result) == 1 + + +@pytest.mark.anyio +async def test_get_fuel_code_by_name(fuel_code_repo, mock_db): + fc = FuelCode(fuel_code_id=50, fuel_suffix="150.0") + mock_result = MagicMock() + mock_result.scalar_one_or_none.return_value = fc + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_fuel_code_by_name("BC150.0") + assert result == fc + + +@pytest.mark.anyio +async def test_get_provision_of_the_act_by_name(fuel_code_repo, mock_db): + poa = ProvisionOfTheAct(provision_of_the_act_id=1, name="Act Name") + mock_result = MagicMock() + mock_result.scalar_one_or_none.return_value = poa + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_provision_of_the_act_by_name("Act Name") + assert result == poa + + +@pytest.mark.anyio +async def test_get_energy_effectiveness_ratio(fuel_code_repo, mock_db): + eer = EnergyEffectivenessRatio(eer_id=1, ratio=1.5) + mock_result = MagicMock() + mock_result.scalars.return_value.first.return_value = eer + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_energy_effectiveness_ratio(1, 2, 3) + assert result == eer + + +@pytest.mark.anyio +async def test_get_target_carbon_intensities(fuel_code_repo, mock_db): + tci = TargetCarbonIntensity( + target_carbon_intensity_id=1, target_carbon_intensity=50.0 + ) + mock_result = MagicMock() + mock_result.scalars.return_value.all.return_value = [tci] + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_target_carbon_intensities(1, "2024") + assert len(result) == 1 + assert result[0] == tci + + +@pytest.mark.anyio +async def test_get_standardized_fuel_data(fuel_code_repo, mock_db): + # Mock dependencies + mock_fuel_type = FuelType( + fuel_type_id=1, fuel_type="Diesel", default_carbon_intensity=80.0 + ) + mock_db.get_one.return_value = mock_fuel_type + mock_db.execute.side_effect = [ + # energy density + MagicMock( + scalars=MagicMock( + return_value=MagicMock( + first=MagicMock(return_value=EnergyDensity(density=35.0)) + ) + ) + ), + # eer + MagicMock( + scalars=MagicMock( + return_value=MagicMock( + first=MagicMock(return_value=EnergyEffectivenessRatio(ratio=2.0)) + ) + ) + ), + # target carbon intensities + MagicMock( + scalars=MagicMock( + return_value=MagicMock( + all=MagicMock( + return_value=[ + TargetCarbonIntensity(target_carbon_intensity=50.0) + ] + ) + ) + ) + ), + # additional carbon intensity + MagicMock( + scalars=MagicMock( + return_value=MagicMock( + one_or_none=MagicMock( + return_value=AdditionalCarbonIntensity(intensity=5.0) + ) + ) + ) + ), + ] + + result = await fuel_code_repo.get_standardized_fuel_data( + fuel_type_id=1, fuel_category_id=2, end_use_id=3, compliance_period="2024" + ) + assert result.effective_carbon_intensity == 80.0 + assert result.target_ci == 50.0 + assert result.eer == 2.0 + assert result.energy_density == 35.0 + assert result.uci == 5.0 + + +@pytest.mark.anyio +async def test_get_additional_carbon_intensity(fuel_code_repo, mock_db): + aci = AdditionalCarbonIntensity(additional_uci_id=1, intensity=10.0) + mock_result = MagicMock() + mock_result.scalars.return_value.one_or_none.return_value = aci + mock_db.execute.return_value = mock_result + + result = await fuel_code_repo.get_additional_carbon_intensity(1, 2) + assert result == aci diff --git a/backend/lcfs/web/api/fuel_code/repo.py b/backend/lcfs/web/api/fuel_code/repo.py index 4cc699008..594bd156f 100644 --- a/backend/lcfs/web/api/fuel_code/repo.py +++ b/backend/lcfs/web/api/fuel_code/repo.py @@ -515,7 +515,7 @@ async def get_distinct_fuel_codes_by_code( @repo_handler async def get_fuel_code_by_code_prefix( self, fuel_suffix: str, prefix: str - ) -> List[str]: + ) -> list[FuelCodeCloneSchema]: query = ( select(FuelCode) .options( @@ -751,7 +751,7 @@ async def get_fuel_code_by_name(self, fuel_code: str) -> FuelCode: .options( contains_eager(FuelCode.fuel_code_prefix), joinedload(FuelCode.fuel_code_status), - joinedload(FuelCode.fuel_code_type), + joinedload(FuelCode.fuel_type), ) .where( and_( From 8b438ffcbb2b1522e37d11ddb45edcc32379b50d Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Thu, 5 Dec 2024 13:40:55 -0700 Subject: [PATCH 03/15] Add organization field to FSE --- .../versions/2024-12-05-22-59_9206124a098b.py | 25 ++++++++++++ .../models/compliance/FinalSupplyEquipment.py | 1 + .../lcfs/web/api/compliance_report/schema.py | 5 +-- .../web/api/final_supply_equipment/repo.py | 39 +++++++++++++++++-- .../web/api/final_supply_equipment/schema.py | 2 + .../api/final_supply_equipment/services.py | 8 +++- .../locales/en/finalSupplyEquipment.json | 1 + .../FinalSupplyEquipmentSummary.jsx | 6 +++ .../views/FinalSupplyEquipments/_schema.jsx | 38 +++++++++++++++++- 9 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 backend/lcfs/db/migrations/versions/2024-12-05-22-59_9206124a098b.py diff --git a/backend/lcfs/db/migrations/versions/2024-12-05-22-59_9206124a098b.py b/backend/lcfs/db/migrations/versions/2024-12-05-22-59_9206124a098b.py new file mode 100644 index 000000000..a32a83434 --- /dev/null +++ b/backend/lcfs/db/migrations/versions/2024-12-05-22-59_9206124a098b.py @@ -0,0 +1,25 @@ +"""Add Organization to FSE + +Revision ID: 9206124a098b +Revises: aeaa26f5cdd5 +Create Date: 2024-12-04 09:59:22.876386 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '9206124a098b' +down_revision = '8491890dd688' +branch_labels = None +depends_on = None + + +def upgrade(): + # Add the column 'organization' to 'final_supply_equipment' table + op.add_column("final_supply_equipment", sa.Column("organization", sa.String(), nullable=True)) + + +def downgrade(): + # Remove the column 'organization' from 'final_supply_equipment' table + op.drop_column("final_supply_equipment", "organization") \ No newline at end of file diff --git a/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py b/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py index e3b8d5685..263f38914 100644 --- a/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py +++ b/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py @@ -123,6 +123,7 @@ class FinalSupplyEquipment(BaseModel, Auditable): Double, nullable=False, comment="The longitude of the equipment location." ) notes = Column(Text, comment="Any additional notes related to the equipment.") + organization = Column(Text, comment="External organization.") # relationships compliance_report = relationship( diff --git a/backend/lcfs/web/api/compliance_report/schema.py b/backend/lcfs/web/api/compliance_report/schema.py index 0f157be8b..5d6f1ec1e 100644 --- a/backend/lcfs/web/api/compliance_report/schema.py +++ b/backend/lcfs/web/api/compliance_report/schema.py @@ -40,10 +40,6 @@ class CompliancePeriodSchema(BaseSchema): display_order: Optional[int] = None -class ComplianceReportOrganizationSchema(BaseSchema): - organization_id: int - name: str - class SummarySchema(BaseSchema): summary_id: int @@ -118,6 +114,7 @@ class FSEOptionsSchema(BaseSchema): class FinalSupplyEquipmentSchema(BaseSchema): final_supply_equipment_id: int compliance_report_id: int + organization: str supply_from_date: date supply_to_date: date registration_nbr: str diff --git a/backend/lcfs/web/api/final_supply_equipment/repo.py b/backend/lcfs/web/api/final_supply_equipment/repo.py index 398f01585..55763c0aa 100644 --- a/backend/lcfs/web/api/final_supply_equipment/repo.py +++ b/backend/lcfs/web/api/final_supply_equipment/repo.py @@ -1,6 +1,6 @@ import structlog from typing import List, Tuple -from lcfs.db.models.compliance import EndUserType, FinalSupplyEquipment +from lcfs.db.models.compliance import EndUserType, FinalSupplyEquipment, ComplianceReport from lcfs.db.models.compliance.FinalSupplyEquipmentRegNumber import ( FinalSupplyEquipmentRegNumber, ) @@ -27,8 +27,14 @@ def __init__(self, db: AsyncSession = Depends(get_async_db_session)): @repo_handler async def get_fse_options( - self, - ) -> Tuple[List[EndUseType], List[LevelOfEquipment], List[FuelMeasurementType], List[PortsEnum]]: + self, organization + ) -> Tuple[ + List[EndUseType], + List[LevelOfEquipment], + List[FuelMeasurementType], + List[PortsEnum], + List[str], + ]: """ Retrieve all FSE options in a single database transaction """ @@ -37,13 +43,15 @@ async def get_fse_options( levels_of_equipment = await self.get_levels_of_equipment() fuel_measurement_types = await self.get_fuel_measurement_types() intended_user_types = await self.get_intended_user_types() + organizations = await self.get_organizations(organization) ports = list(PortsEnum) return ( intended_use_types, levels_of_equipment, fuel_measurement_types, intended_user_types, - ports + ports, + organizations, ) async def get_intended_use_types(self) -> List[EndUseType]: @@ -94,6 +102,29 @@ async def get_intended_user_types(self) -> List[EndUserType]: .all() ) + async def get_organizations(self, organization) -> List[str]: + """ + Retrieve unique organization names for Final Supply Equipment records + associated with the given organization_id via ComplianceReport. + + Args: + organization_id (int): The ID of the organization. + + Returns: + List[str]: A list of unique organization names. + """ + organization_names = ( + await self.db.execute( + select(distinct(FinalSupplyEquipment.organization)) + .join(ComplianceReport, FinalSupplyEquipment.compliance_report_id == ComplianceReport.compliance_report_id) + .filter(ComplianceReport.organization_id == organization.organization_id) + .filter(FinalSupplyEquipment.organization.isnot(None)) + ) + ).all() + + # Extract strings from the list of tuples + return [name[0] for name in organization_names] + @repo_handler async def get_intended_user_by_name(self, intended_user: str) -> EndUseType: """ diff --git a/backend/lcfs/web/api/final_supply_equipment/schema.py b/backend/lcfs/web/api/final_supply_equipment/schema.py index 38f80b2fa..fbe7ed468 100644 --- a/backend/lcfs/web/api/final_supply_equipment/schema.py +++ b/backend/lcfs/web/api/final_supply_equipment/schema.py @@ -33,11 +33,13 @@ class FSEOptionsSchema(BaseSchema): levels_of_equipment: List[LevelOfEquipmentSchema] intended_user_types: List[EndUserTypeSchema] ports: List[PortsEnum] + organizations: List[str] class FinalSupplyEquipmentCreateSchema(BaseSchema): final_supply_equipment_id: Optional[int] = None compliance_report_id: Optional[int] = None + organization: str supply_from_date: date supply_to_date: date kwh_usage: float diff --git a/backend/lcfs/web/api/final_supply_equipment/services.py b/backend/lcfs/web/api/final_supply_equipment/services.py index 9cc225935..c2d1fb5e8 100644 --- a/backend/lcfs/web/api/final_supply_equipment/services.py +++ b/backend/lcfs/web/api/final_supply_equipment/services.py @@ -29,13 +29,15 @@ def __init__( @service_handler async def get_fse_options(self): """Fetches all FSE options concurrently.""" + organization= self.request.user.organization ( intended_use_types, levels_of_equipment, fuel_measurement_types, intended_user_types, - ports - ) = await self.repo.get_fse_options() + ports, + organizations + ) = await self.repo.get_fse_options(organization) return { "intended_use_types": [ @@ -52,6 +54,7 @@ async def get_fse_options(self): EndUserTypeSchema.model_validate(u) for u in intended_user_types ], "ports": [port.value for port in ports], + "organizations": organizations, } async def convert_to_fse_model(self, fse: FinalSupplyEquipmentCreateSchema): @@ -141,6 +144,7 @@ async def update_final_supply_equipment( if not existing_fse: raise ValueError("final supply equipment not found") + existing_fse.organization = fse_data.organization existing_fse.kwh_usage = fse_data.kwh_usage existing_fse.serial_nbr = fse_data.serial_nbr existing_fse.manufacturer = fse_data.manufacturer diff --git a/frontend/src/assets/locales/en/finalSupplyEquipment.json b/frontend/src/assets/locales/en/finalSupplyEquipment.json index 00e74933f..b8449d574 100644 --- a/frontend/src/assets/locales/en/finalSupplyEquipment.json +++ b/frontend/src/assets/locales/en/finalSupplyEquipment.json @@ -27,6 +27,7 @@ "rows": "rows", "finalSupplyEquipmentColLabels": { "complianceReportId": "Compliance Report ID", + "organization": "Organization", "supplyFrom": "Supply date range", "kwhUsage":"kWh usage", "supplyFromDate": "Dates of supply from", diff --git a/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx b/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx index 84437a91b..81ce8415d 100644 --- a/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx +++ b/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx @@ -48,6 +48,12 @@ export const FinalSupplyEquipmentSummary = ({ data }) => { ) const columns = useMemo( () => [ + { + headerName: t( + 'finalSupplyEquipment:finalSupplyEquipmentColLabels.organization' + ), + field: 'organization' + }, { headerName: t( 'finalSupplyEquipment:finalSupplyEquipmentColLabels.supplyFromDate' diff --git a/frontend/src/views/FinalSupplyEquipments/_schema.jsx b/frontend/src/views/FinalSupplyEquipments/_schema.jsx index 2974a9725..244eaa112 100644 --- a/frontend/src/views/FinalSupplyEquipments/_schema.jsx +++ b/frontend/src/views/FinalSupplyEquipments/_schema.jsx @@ -12,7 +12,7 @@ import i18n from '@/i18n' import { actions, validation } from '@/components/BCDataGrid/columns' import moment from 'moment' import { CommonArrayRenderer } from '@/utils/grid/cellRenderers' -import { StandardCellErrors } from '@/utils/grid/errorRenderers' +import { StandardCellWarningAndErrors, StandardCellErrors } from '@/utils/grid/errorRenderers' import { apiRoutes } from '@/constants/routes' import { numberFormatter } from '@/utils/formatters.js' @@ -41,6 +41,42 @@ export const finalSupplyEquipmentColDefs = ( cellDataType: 'text', hide: true }, + { + field: 'organization', + headerComponent: RequiredHeader, + headerName: i18n.t( + 'finalSupplyEquipment:finalSupplyEquipmentColLabels.organization' + ), + cellEditor: AutocompleteCellEditor, + cellRenderer: (params) => + params.value || + (!params.value && Select), + cellEditorParams: { + options: optionsData?.organizations?.sort() || [], + multiple: false, + disableCloseOnSelect: false, + freeSolo: true, + openOnFocus: true, + }, + cellStyle: (params) => + StandardCellWarningAndErrors(params, errors), + suppressKeyboardEvent, + minWidth: 260, + editable: true, + valueGetter: (params) => { + return params.data?.organization || ''; + }, + valueSetter: (params) => { + if (params.newValue) { + const isValidOrganization = optionsData?.organizations.includes(params.newValue); + + params.data.organization = isValidOrganization ? params.newValue : params.newValue; + return true; + } + return false; + }, + tooltipValueGetter: (params) => "Select the organization from the list" + }, { field: 'supplyFrom', headerName: i18n.t( From 81857ea7f1476c5636f7df81432654ddeecd42e5 Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Mon, 9 Dec 2024 10:02:06 -0700 Subject: [PATCH 04/15] rename organization for organization_name --- ...24a098b.py => 2024-12-06-09-59_9206124a098b.py} | 12 ++++++------ .../db/models/compliance/FinalSupplyEquipment.py | 2 +- backend/lcfs/web/api/compliance_report/schema.py | 2 +- .../lcfs/web/api/final_supply_equipment/repo.py | 10 +++++----- .../lcfs/web/api/final_supply_equipment/schema.py | 4 ++-- .../web/api/final_supply_equipment/services.py | 8 ++++---- .../assets/locales/en/finalSupplyEquipment.json | 2 +- .../FinalSupplyEquipmentSummary.jsx | 4 ++-- .../src/views/FinalSupplyEquipments/_schema.jsx | 14 +++++++------- 9 files changed, 29 insertions(+), 29 deletions(-) rename backend/lcfs/db/migrations/versions/{2024-12-05-22-59_9206124a098b.py => 2024-12-06-09-59_9206124a098b.py} (53%) diff --git a/backend/lcfs/db/migrations/versions/2024-12-05-22-59_9206124a098b.py b/backend/lcfs/db/migrations/versions/2024-12-06-09-59_9206124a098b.py similarity index 53% rename from backend/lcfs/db/migrations/versions/2024-12-05-22-59_9206124a098b.py rename to backend/lcfs/db/migrations/versions/2024-12-06-09-59_9206124a098b.py index a32a83434..fc805ff14 100644 --- a/backend/lcfs/db/migrations/versions/2024-12-05-22-59_9206124a098b.py +++ b/backend/lcfs/db/migrations/versions/2024-12-06-09-59_9206124a098b.py @@ -1,4 +1,4 @@ -"""Add Organization to FSE +"""Add Organization name to FSE Revision ID: 9206124a098b Revises: aeaa26f5cdd5 @@ -10,16 +10,16 @@ # revision identifiers, used by Alembic. revision = '9206124a098b' -down_revision = '8491890dd688' +down_revision = '26ab15f8ab18' branch_labels = None depends_on = None def upgrade(): - # Add the column 'organization' to 'final_supply_equipment' table - op.add_column("final_supply_equipment", sa.Column("organization", sa.String(), nullable=True)) + # Add the column 'organization_name' to 'final_supply_equipment' table + op.add_column("final_supply_equipment", sa.Column("organization_name", sa.String(), nullable=True)) def downgrade(): - # Remove the column 'organization' from 'final_supply_equipment' table - op.drop_column("final_supply_equipment", "organization") \ No newline at end of file + # Remove the column 'organization_name' from 'final_supply_equipment' table + op.drop_column("final_supply_equipment", "organization_name") \ No newline at end of file diff --git a/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py b/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py index 263f38914..90bd37b27 100644 --- a/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py +++ b/backend/lcfs/db/models/compliance/FinalSupplyEquipment.py @@ -123,7 +123,7 @@ class FinalSupplyEquipment(BaseModel, Auditable): Double, nullable=False, comment="The longitude of the equipment location." ) notes = Column(Text, comment="Any additional notes related to the equipment.") - organization = Column(Text, comment="External organization.") + organization_name = Column(Text, comment="External organization name.") # relationships compliance_report = relationship( diff --git a/backend/lcfs/web/api/compliance_report/schema.py b/backend/lcfs/web/api/compliance_report/schema.py index 5d6f1ec1e..9eb215c53 100644 --- a/backend/lcfs/web/api/compliance_report/schema.py +++ b/backend/lcfs/web/api/compliance_report/schema.py @@ -114,7 +114,7 @@ class FSEOptionsSchema(BaseSchema): class FinalSupplyEquipmentSchema(BaseSchema): final_supply_equipment_id: int compliance_report_id: int - organization: str + organization_name: str supply_from_date: date supply_to_date: date registration_nbr: str diff --git a/backend/lcfs/web/api/final_supply_equipment/repo.py b/backend/lcfs/web/api/final_supply_equipment/repo.py index 55763c0aa..b3680584f 100644 --- a/backend/lcfs/web/api/final_supply_equipment/repo.py +++ b/backend/lcfs/web/api/final_supply_equipment/repo.py @@ -43,7 +43,7 @@ async def get_fse_options( levels_of_equipment = await self.get_levels_of_equipment() fuel_measurement_types = await self.get_fuel_measurement_types() intended_user_types = await self.get_intended_user_types() - organizations = await self.get_organizations(organization) + organization_names = await self.get_organization_names(organization) ports = list(PortsEnum) return ( intended_use_types, @@ -51,7 +51,7 @@ async def get_fse_options( fuel_measurement_types, intended_user_types, ports, - organizations, + organization_names, ) async def get_intended_use_types(self) -> List[EndUseType]: @@ -102,7 +102,7 @@ async def get_intended_user_types(self) -> List[EndUserType]: .all() ) - async def get_organizations(self, organization) -> List[str]: + async def get_organization_names(self, organization) -> List[str]: """ Retrieve unique organization names for Final Supply Equipment records associated with the given organization_id via ComplianceReport. @@ -115,10 +115,10 @@ async def get_organizations(self, organization) -> List[str]: """ organization_names = ( await self.db.execute( - select(distinct(FinalSupplyEquipment.organization)) + select(distinct(FinalSupplyEquipment.organization_name)) .join(ComplianceReport, FinalSupplyEquipment.compliance_report_id == ComplianceReport.compliance_report_id) .filter(ComplianceReport.organization_id == organization.organization_id) - .filter(FinalSupplyEquipment.organization.isnot(None)) + .filter(FinalSupplyEquipment.organization_name.isnot(None)) ) ).all() diff --git a/backend/lcfs/web/api/final_supply_equipment/schema.py b/backend/lcfs/web/api/final_supply_equipment/schema.py index fbe7ed468..2dc81e8f3 100644 --- a/backend/lcfs/web/api/final_supply_equipment/schema.py +++ b/backend/lcfs/web/api/final_supply_equipment/schema.py @@ -33,13 +33,13 @@ class FSEOptionsSchema(BaseSchema): levels_of_equipment: List[LevelOfEquipmentSchema] intended_user_types: List[EndUserTypeSchema] ports: List[PortsEnum] - organizations: List[str] + organization_names: List[str] class FinalSupplyEquipmentCreateSchema(BaseSchema): final_supply_equipment_id: Optional[int] = None compliance_report_id: Optional[int] = None - organization: str + organization_name: str supply_from_date: date supply_to_date: date kwh_usage: float diff --git a/backend/lcfs/web/api/final_supply_equipment/services.py b/backend/lcfs/web/api/final_supply_equipment/services.py index c2d1fb5e8..a70b1ce4b 100644 --- a/backend/lcfs/web/api/final_supply_equipment/services.py +++ b/backend/lcfs/web/api/final_supply_equipment/services.py @@ -29,14 +29,14 @@ def __init__( @service_handler async def get_fse_options(self): """Fetches all FSE options concurrently.""" - organization= self.request.user.organization + organization = self.request.user.organization ( intended_use_types, levels_of_equipment, fuel_measurement_types, intended_user_types, ports, - organizations + organization_names, ) = await self.repo.get_fse_options(organization) return { @@ -54,7 +54,7 @@ async def get_fse_options(self): EndUserTypeSchema.model_validate(u) for u in intended_user_types ], "ports": [port.value for port in ports], - "organizations": organizations, + "organization_names": organization_names, } async def convert_to_fse_model(self, fse: FinalSupplyEquipmentCreateSchema): @@ -144,7 +144,7 @@ async def update_final_supply_equipment( if not existing_fse: raise ValueError("final supply equipment not found") - existing_fse.organization = fse_data.organization + existing_fse.organization_name = fse_data.organization_name existing_fse.kwh_usage = fse_data.kwh_usage existing_fse.serial_nbr = fse_data.serial_nbr existing_fse.manufacturer = fse_data.manufacturer diff --git a/frontend/src/assets/locales/en/finalSupplyEquipment.json b/frontend/src/assets/locales/en/finalSupplyEquipment.json index b8449d574..d48862f59 100644 --- a/frontend/src/assets/locales/en/finalSupplyEquipment.json +++ b/frontend/src/assets/locales/en/finalSupplyEquipment.json @@ -27,7 +27,7 @@ "rows": "rows", "finalSupplyEquipmentColLabels": { "complianceReportId": "Compliance Report ID", - "organization": "Organization", + "organizationName": "Organization", "supplyFrom": "Supply date range", "kwhUsage":"kWh usage", "supplyFromDate": "Dates of supply from", diff --git a/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx b/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx index 81ce8415d..1a2f7851e 100644 --- a/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx +++ b/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx @@ -50,9 +50,9 @@ export const FinalSupplyEquipmentSummary = ({ data }) => { () => [ { headerName: t( - 'finalSupplyEquipment:finalSupplyEquipmentColLabels.organization' + 'finalSupplyEquipment:finalSupplyEquipmentColLabels.organizationName' ), - field: 'organization' + field: 'organizationName' }, { headerName: t( diff --git a/frontend/src/views/FinalSupplyEquipments/_schema.jsx b/frontend/src/views/FinalSupplyEquipments/_schema.jsx index 244eaa112..b00d5f437 100644 --- a/frontend/src/views/FinalSupplyEquipments/_schema.jsx +++ b/frontend/src/views/FinalSupplyEquipments/_schema.jsx @@ -42,17 +42,17 @@ export const finalSupplyEquipmentColDefs = ( hide: true }, { - field: 'organization', + field: 'organizationName', headerComponent: RequiredHeader, headerName: i18n.t( - 'finalSupplyEquipment:finalSupplyEquipmentColLabels.organization' + 'finalSupplyEquipment:finalSupplyEquipmentColLabels.organizationName' ), cellEditor: AutocompleteCellEditor, cellRenderer: (params) => params.value || (!params.value && Select), cellEditorParams: { - options: optionsData?.organizations?.sort() || [], + options: optionsData?.organizationNames?.sort() || [], multiple: false, disableCloseOnSelect: false, freeSolo: true, @@ -64,18 +64,18 @@ export const finalSupplyEquipmentColDefs = ( minWidth: 260, editable: true, valueGetter: (params) => { - return params.data?.organization || ''; + return params.data?.organizationName || ''; }, valueSetter: (params) => { if (params.newValue) { - const isValidOrganization = optionsData?.organizations.includes(params.newValue); + const isValidOrganizationName = optionsData?.organizationNames.includes(params.newValue); - params.data.organization = isValidOrganization ? params.newValue : params.newValue; + params.data.organizationName = isValidOrganizationName ? params.newValue : params.newValue; return true; } return false; }, - tooltipValueGetter: (params) => "Select the organization from the list" + tooltipValueGetter: (params) => "Select the organization name from the list" }, { field: 'supplyFrom', From 04f1b780b597c1d8964d3bfa36aa702bb4d9d390 Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Wed, 11 Dec 2024 12:12:19 -0700 Subject: [PATCH 05/15] fixing migration issues --- .../db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py b/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py index d812b2a94..8ec2b8223 100644 --- a/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py +++ b/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py @@ -11,7 +11,7 @@ # revision identifiers, used by Alembic. revision = "cd8698fe40e6" -down_revision = "26ab15f8ab18" +down_revision = "9206124a098b" branch_labels = None depends_on = None From 7450fd1b49d06f920ad4f4a132285cb5d96bab93 Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Mon, 9 Dec 2024 14:22:36 -0700 Subject: [PATCH 06/15] Update fuel type for other_uses --- .../versions/2024-12-09-19-31_7ae38a8413ab.py | 95 +++++++++++++++++++ backend/lcfs/web/api/other_uses/repo.py | 90 ++++++++++++++++-- 2 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py diff --git a/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py b/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py new file mode 100644 index 000000000..da29c2fc1 --- /dev/null +++ b/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py @@ -0,0 +1,95 @@ +"""Update Fuel Types measured in volume to be other-uses + +Revision ID: 7ae38a8413ab +Revises: 26ab15f8ab18 +Create Date: 2024-12-09 19:31:18.199089 + +""" + +import sqlalchemy as sa +from alembic import op +from datetime import datetime + +# revision identifiers, used by Alembic. +revision = "7ae38a8413ab" +down_revision = "26ab15f8ab18" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + current_time = datetime.now() + + # Update the `other_uses_fossil_derived` field for all specified fuel types + op.execute( + f""" + UPDATE fuel_type + SET other_uses_fossil_derived = true, + update_date = '{current_time}', + update_user = 'no_user' + WHERE fuel_type IN ( + 'Alternative jet fuel', + 'Biodiesel', + 'Ethanol', + 'HDRD', + 'Renewable gasoline', + 'Renewable naphtha' + ) + """ + ) + + # Update the `other_uses_fossil_derived` field for all specified fuel types + op.execute( + f""" + UPDATE fuel_type + SET other_uses_fossil_derived = false, + update_date = '{current_time}', + update_user = 'no_user' + WHERE fuel_type IN ( + 'CNG', + 'Electricity', + 'Hydrogen', + 'LNG', + 'Propane' + ) + """ + ) + + +def downgrade() -> None: + current_time = datetime.now() + + # Revert the `other_uses_fossil_derived` field to false for the first set of fuel types + op.execute( + f""" + UPDATE fuel_type + SET other_uses_fossil_derived = false, + update_date = '{current_time}', + update_user = 'no_user' + WHERE fuel_type IN ( + 'Alternative jet fuel', + 'Biodiesel', + 'Ethanol', + 'HDRD', + 'Renewable gasoline', + 'Renewable naphtha' + ) + """ + ) + + # Revert the `other_uses_fossil_derived` field to true for the second set of fuel types + op.execute( + f""" + UPDATE fuel_type + SET other_uses_fossil_derived = true, + update_date = '{current_time}', + update_user = 'no_user' + WHERE fuel_type IN ( + 'CNG', + 'Electricity', + 'Hydrogen', + 'LNG', + 'Propane' + ) + """ + ) diff --git a/backend/lcfs/web/api/other_uses/repo.py b/backend/lcfs/web/api/other_uses/repo.py index 68a8a434a..8e0f5ca4d 100644 --- a/backend/lcfs/web/api/other_uses/repo.py +++ b/backend/lcfs/web/api/other_uses/repo.py @@ -1,20 +1,21 @@ import structlog -from typing import List, Optional, Tuple, Any +from datetime import date +from typing import List, Optional, Tuple, Dict, Any from fastapi import Depends - from lcfs.db.base import ActionTypeEnum, UserTypeEnum from lcfs.db.dependencies import get_async_db_session -from sqlalchemy import select, delete, func, case, and_ -from sqlalchemy.orm import joinedload +from sqlalchemy import select, delete, func, case, and_, or_ +from sqlalchemy.orm import joinedload, contains_eager from sqlalchemy.ext.asyncio import AsyncSession from lcfs.db.models.compliance import ComplianceReport from lcfs.db.models.compliance.OtherUses import OtherUses from lcfs.db.models.fuel.ProvisionOfTheAct import ProvisionOfTheAct from lcfs.db.models.fuel.FuelCode import FuelCode -from lcfs.db.models.fuel.FuelType import QuantityUnitsEnum +from lcfs.db.models.fuel.FuelType import FuelType, QuantityUnitsEnum +from lcfs.db.models.fuel.FuelInstance import FuelInstance from lcfs.web.api.fuel_code.repo import FuelCodeRepository from lcfs.web.api.other_uses.schema import OtherUsesSchema from lcfs.web.api.base import PaginationRequestSchema @@ -37,7 +38,7 @@ def __init__( async def get_table_options(self) -> dict: """Get all table options""" fuel_categories = await self.fuel_code_repo.get_fuel_categories() - fuel_types = await self.fuel_code_repo.get_formatted_fuel_types() + fuel_types = await self.get_formatted_fuel_types() expected_uses = await self.fuel_code_repo.get_expected_use_types() units_of_measure = [unit.value for unit in QuantityUnitsEnum] provisions_of_the_act = ( @@ -302,3 +303,80 @@ async def get_other_use_version_by_user( result = await self.db.execute(query) return result.scalars().first() + + @repo_handler + async def get_formatted_fuel_types(self) -> List[Dict[str, Any]]: + """Get all fuel type options with their associated fuel categories and fuel codes for other uses""" + # Define the filtering conditions for fuel codes + current_date = date.today() + fuel_code_filters = ( + or_(FuelCode.effective_date == None, FuelCode.effective_date <= current_date) + & or_(FuelCode.expiration_date == None, FuelCode.expiration_date > current_date) + & (FuelType.other_uses_fossil_derived == True) + ) + + # Build the query with filtered fuel_codes + query = ( + select(FuelType) + .outerjoin(FuelType.fuel_instances) + .outerjoin(FuelInstance.fuel_category) + .outerjoin(FuelType.fuel_codes) + .where(fuel_code_filters) + .options( + contains_eager(FuelType.fuel_instances).contains_eager( + FuelInstance.fuel_category + ), + contains_eager(FuelType.fuel_codes), + joinedload(FuelType.provision_1), + joinedload(FuelType.provision_2), + ) + ) + + result = await self.db.execute(query) + fuel_types = result.unique().scalars().all() + + # Prepare the data in the format matching your schema + formatted_fuel_types = [] + for fuel_type in fuel_types: + formatted_fuel_type = { + "fuel_type_id": fuel_type.fuel_type_id, + "fuel_type": fuel_type.fuel_type, + "default_carbon_intensity": fuel_type.default_carbon_intensity, + "units": fuel_type.units if fuel_type.units else None, + "unrecognized": fuel_type.unrecognized, + "fuel_categories": [ + { + "fuel_category_id": fc.fuel_category.fuel_category_id, + "category": fc.fuel_category.category, + } + for fc in fuel_type.fuel_instances + ], + "fuel_codes": [ + { + "fuel_code_id": fc.fuel_code_id, + "fuel_code": fc.fuel_code, + "carbon_intensity": fc.carbon_intensity, + } + for fc in fuel_type.fuel_codes + ], + "provision_of_the_act": [], + } + + if fuel_type.provision_1: + formatted_fuel_type["provision_of_the_act"].append( + { + "provision_of_the_act_id": fuel_type.provision_1_id, + "name": fuel_type.provision_1.name, + } + ) + + if fuel_type.provision_2: + formatted_fuel_type["provision_of_the_act"].append( + { + "provision_of_the_act_id": fuel_type.provision_2_id, + "name": fuel_type.provision_2.name, + } + ) + formatted_fuel_types.append(formatted_fuel_type) + + return formatted_fuel_types \ No newline at end of file From 4573d8f5bfc4760526b7f5db2be9d81410a9ca03 Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Mon, 9 Dec 2024 16:32:10 -0700 Subject: [PATCH 07/15] updating pytest --- .../tests/other_uses/test_other_uses_repo.py | 27 ++++++++++++++----- backend/lcfs/web/api/other_uses/repo.py | 6 ++--- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/backend/lcfs/tests/other_uses/test_other_uses_repo.py b/backend/lcfs/tests/other_uses/test_other_uses_repo.py index 8bd39f562..97b5308f5 100644 --- a/backend/lcfs/tests/other_uses/test_other_uses_repo.py +++ b/backend/lcfs/tests/other_uses/test_other_uses_repo.py @@ -11,14 +11,19 @@ @pytest.fixture -def mock_db_session(): +def mock_query_result(): + # Setup mock for database query result chain + mock_result = AsyncMock() + mock_result.unique = MagicMock(return_value=mock_result) + mock_result.scalars = MagicMock(return_value=mock_result) + mock_result.all = MagicMock(return_value=[MagicMock(spec=OtherUses)]) + return mock_result + + +@pytest.fixture +def mock_db_session(mock_query_result): session = MagicMock(spec=AsyncSession) - execute_result = AsyncMock() - execute_result.unique = MagicMock(return_value=execute_result) - execute_result.scalars = MagicMock(return_value=execute_result) - execute_result.all = MagicMock(return_value=[MagicMock(spec=OtherUses)]) - execute_result.first = MagicMock(return_value=MagicMock(spec=OtherUses)) - session.execute.return_value = execute_result + session.execute = AsyncMock(return_value=mock_query_result) return session @@ -29,6 +34,14 @@ def other_uses_repo(mock_db_session): repo.fuel_code_repo.get_fuel_categories = AsyncMock(return_value=[]) repo.fuel_code_repo.get_fuel_types = AsyncMock(return_value=[]) repo.fuel_code_repo.get_expected_use_types = AsyncMock(return_value=[]) + + # Mock for local get_formatted_fuel_types method + async def mock_get_formatted_fuel_types(): + mock_result = await mock_db_session.execute(AsyncMock()) + return mock_result.unique().scalars().all() + + repo.get_formatted_fuel_types = AsyncMock(side_effect=mock_get_formatted_fuel_types) + return repo diff --git a/backend/lcfs/web/api/other_uses/repo.py b/backend/lcfs/web/api/other_uses/repo.py index 8e0f5ca4d..595de5882 100644 --- a/backend/lcfs/web/api/other_uses/repo.py +++ b/backend/lcfs/web/api/other_uses/repo.py @@ -76,7 +76,7 @@ async def get_latest_other_uses_by_group_uuid( ) result = await self.db.execute(query) - return result.scalars().first() + return await result.unique().scalars().first() @repo_handler async def get_other_uses(self, compliance_report_id: int) -> List[OtherUsesSchema]: @@ -302,7 +302,7 @@ async def get_other_use_version_by_user( ) result = await self.db.execute(query) - return result.scalars().first() + return await result.scalars().first() @repo_handler async def get_formatted_fuel_types(self) -> List[Dict[str, Any]]: @@ -333,7 +333,7 @@ async def get_formatted_fuel_types(self) -> List[Dict[str, Any]]: ) result = await self.db.execute(query) - fuel_types = result.unique().scalars().all() + fuel_types = await result.unique().scalars().all() # Prepare the data in the format matching your schema formatted_fuel_types = [] From 8580d716d28eec96ef590414581998e82b2e9c12 Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Wed, 11 Dec 2024 10:26:34 -0700 Subject: [PATCH 08/15] changes in await --- .../tests/other_uses/test_other_uses_repo.py | 19 +++++++++---------- backend/lcfs/web/api/other_uses/repo.py | 15 ++++++++++----- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/backend/lcfs/tests/other_uses/test_other_uses_repo.py b/backend/lcfs/tests/other_uses/test_other_uses_repo.py index 97b5308f5..8ef79cd70 100644 --- a/backend/lcfs/tests/other_uses/test_other_uses_repo.py +++ b/backend/lcfs/tests/other_uses/test_other_uses_repo.py @@ -207,22 +207,21 @@ async def test_get_latest_other_uses_by_group_uuid(other_uses_repo, mock_db_sess mock_other_use_gov.user_type = UserTypeEnum.GOVERNMENT mock_other_use_gov.version = 2 - mock_other_use_supplier = MagicMock(spec=OtherUses) - mock_other_use_supplier.user_type = UserTypeEnum.SUPPLIER - mock_other_use_supplier.version = 3 - - # Mock response with both government and supplier versions - mock_db_session.execute.return_value.scalars.return_value.first.side_effect = [ - mock_other_use_gov, - mock_other_use_supplier, - ] + # Setup mock result chain + mock_result = AsyncMock() + mock_result.unique = MagicMock(return_value=mock_result) + mock_result.scalars = MagicMock(return_value=mock_result) + mock_result.first = MagicMock(return_value=mock_other_use_gov) + + # Configure mock db session + mock_db_session.execute = AsyncMock(return_value=mock_result) + other_uses_repo.db = mock_db_session result = await other_uses_repo.get_latest_other_uses_by_group_uuid(group_uuid) assert result.user_type == UserTypeEnum.GOVERNMENT assert result.version == 2 - @pytest.mark.anyio async def test_get_other_use_version_by_user(other_uses_repo, mock_db_session): group_uuid = "test-group-uuid" diff --git a/backend/lcfs/web/api/other_uses/repo.py b/backend/lcfs/web/api/other_uses/repo.py index 595de5882..9f49a3d5d 100644 --- a/backend/lcfs/web/api/other_uses/repo.py +++ b/backend/lcfs/web/api/other_uses/repo.py @@ -76,7 +76,7 @@ async def get_latest_other_uses_by_group_uuid( ) result = await self.db.execute(query) - return await result.unique().scalars().first() + return result.unique().scalars().first() @repo_handler async def get_other_uses(self, compliance_report_id: int) -> List[OtherUsesSchema]: @@ -310,8 +310,13 @@ async def get_formatted_fuel_types(self) -> List[Dict[str, Any]]: # Define the filtering conditions for fuel codes current_date = date.today() fuel_code_filters = ( - or_(FuelCode.effective_date == None, FuelCode.effective_date <= current_date) - & or_(FuelCode.expiration_date == None, FuelCode.expiration_date > current_date) + or_( + FuelCode.effective_date == None, FuelCode.effective_date <= current_date + ) + & or_( + FuelCode.expiration_date == None, + FuelCode.expiration_date > current_date, + ) & (FuelType.other_uses_fossil_derived == True) ) @@ -333,7 +338,7 @@ async def get_formatted_fuel_types(self) -> List[Dict[str, Any]]: ) result = await self.db.execute(query) - fuel_types = await result.unique().scalars().all() + fuel_types = result.unique().scalars().all() # Prepare the data in the format matching your schema formatted_fuel_types = [] @@ -379,4 +384,4 @@ async def get_formatted_fuel_types(self) -> List[Dict[str, Any]]: ) formatted_fuel_types.append(formatted_fuel_type) - return formatted_fuel_types \ No newline at end of file + return formatted_fuel_types From d13cd66f3d745944f5959b705b7567daf3154770 Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Wed, 11 Dec 2024 12:24:47 -0700 Subject: [PATCH 09/15] fixes in migrations --- .../db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py b/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py index 8ec2b8223..3a512b338 100644 --- a/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py +++ b/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py @@ -11,7 +11,7 @@ # revision identifiers, used by Alembic. revision = "cd8698fe40e6" -down_revision = "9206124a098b" +down_revision = "7ae38a8413ab" branch_labels = None depends_on = None From a7e6979af1f6242cc7e72edbcf7f43dc924936d8 Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Wed, 11 Dec 2024 12:26:11 -0700 Subject: [PATCH 10/15] fix migration issue --- .../db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py b/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py index da29c2fc1..0f422117e 100644 --- a/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py +++ b/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py @@ -12,7 +12,7 @@ # revision identifiers, used by Alembic. revision = "7ae38a8413ab" -down_revision = "26ab15f8ab18" +down_revision = "9206124a098b" branch_labels = None depends_on = None From 0253e2ad65b88b158a87701857355eb44cce4f0b Mon Sep 17 00:00:00 2001 From: Arturo Reyes Lopez Date: Wed, 11 Dec 2024 14:17:21 -0700 Subject: [PATCH 11/15] Updating migration to correct down_revision --- .../versions/2024-12-09-22-33_cd8698fe40e6.py | 2 +- ...e38a8413ab.py => 2024-12-09-23-31_7ae38a8413ab.py} | 2 +- backend/lcfs/tests/other_uses/test_other_uses_repo.py | 11 ++++++++--- backend/lcfs/web/api/other_uses/repo.py | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) rename backend/lcfs/db/migrations/versions/{2024-12-09-19-31_7ae38a8413ab.py => 2024-12-09-23-31_7ae38a8413ab.py} (98%) diff --git a/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py b/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py index 3a512b338..8ec2b8223 100644 --- a/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py +++ b/backend/lcfs/db/migrations/versions/2024-12-09-22-33_cd8698fe40e6.py @@ -11,7 +11,7 @@ # revision identifiers, used by Alembic. revision = "cd8698fe40e6" -down_revision = "7ae38a8413ab" +down_revision = "9206124a098b" branch_labels = None depends_on = None diff --git a/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py b/backend/lcfs/db/migrations/versions/2024-12-09-23-31_7ae38a8413ab.py similarity index 98% rename from backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py rename to backend/lcfs/db/migrations/versions/2024-12-09-23-31_7ae38a8413ab.py index 0f422117e..51856f8c4 100644 --- a/backend/lcfs/db/migrations/versions/2024-12-09-19-31_7ae38a8413ab.py +++ b/backend/lcfs/db/migrations/versions/2024-12-09-23-31_7ae38a8413ab.py @@ -12,7 +12,7 @@ # revision identifiers, used by Alembic. revision = "7ae38a8413ab" -down_revision = "9206124a098b" +down_revision = "cd8698fe40e6" branch_labels = None depends_on = None diff --git a/backend/lcfs/tests/other_uses/test_other_uses_repo.py b/backend/lcfs/tests/other_uses/test_other_uses_repo.py index 8ef79cd70..67ea7d1d5 100644 --- a/backend/lcfs/tests/other_uses/test_other_uses_repo.py +++ b/backend/lcfs/tests/other_uses/test_other_uses_repo.py @@ -233,9 +233,14 @@ async def test_get_other_use_version_by_user(other_uses_repo, mock_db_session): mock_other_use.version = version mock_other_use.user_type = user_type - mock_db_session.execute.return_value.scalars.return_value.first.return_value = ( - mock_other_use - ) + # Set up mock result chain + mock_result = AsyncMock() + mock_result.scalars = MagicMock(return_value=mock_result) + mock_result.first = MagicMock(return_value=mock_other_use) + + # Configure mock db session + mock_db_session.execute = AsyncMock(return_value=mock_result) + other_uses_repo.db = mock_db_session result = await other_uses_repo.get_other_use_version_by_user( group_uuid, version, user_type diff --git a/backend/lcfs/web/api/other_uses/repo.py b/backend/lcfs/web/api/other_uses/repo.py index 9f49a3d5d..8e515b484 100644 --- a/backend/lcfs/web/api/other_uses/repo.py +++ b/backend/lcfs/web/api/other_uses/repo.py @@ -302,7 +302,7 @@ async def get_other_use_version_by_user( ) result = await self.db.execute(query) - return await result.scalars().first() + return result.scalars().first() @repo_handler async def get_formatted_fuel_types(self) -> List[Dict[str, Any]]: From ba4e5830a8e4e5197ee09e825b97ff084506b4f0 Mon Sep 17 00:00:00 2001 From: Hamed Valiollahi Bayeki Date: Wed, 11 Dec 2024 13:18:43 -0800 Subject: [PATCH 12/15] refactor: replace typography with bctypography across components for consistency --- .../src/components/BCForm/BCFormCheckbox.jsx | 8 +-- .../src/components/BCForm/BCFormRadio.jsx | 8 +-- frontend/src/components/BCForm/BCFormText.jsx | 7 +-- .../src/components/BCForm/CustomLabel.jsx | 6 +-- .../BCTypography/BCTypographyRoot.jsx | 2 +- frontend/src/components/DisclaimerBanner.jsx | 7 +-- frontend/src/components/Loading.jsx | 6 +-- .../src/components/ProgressBreadcrumb.jsx | 11 ++-- .../Admin/AdminMenu/components/AuditLog.jsx | 6 +-- .../AdminMenu/components/ViewAuditLog.jsx | 26 ++++----- .../AddAllocationAgreements.jsx | 10 ++-- .../views/AllocationAgreements/_schema.jsx | 10 ++-- .../ComplianceReports/ComplianceReports.jsx | 12 +++-- .../EditViewComplianceReport.jsx | 17 +++--- .../components/ActivityListCard.jsx | 11 ++-- .../components/AssessmentCard.jsx | 24 ++++----- .../components/ComplianceReportSummary.jsx | 7 ++- .../components/Introduction.jsx | 22 ++++---- .../components/OrgDetailsCard.jsx | 23 ++++---- .../components/ReportDetails.jsx | 14 ++--- .../AddEditFinalSupplyEquipments.jsx | 10 ++-- .../views/FinalSupplyEquipments/_schema.jsx | 16 +++--- .../FuelCodes/AddFuelCode/AddEditFuelCode.jsx | 10 ++-- .../views/FuelCodes/AddFuelCode/_schema.jsx | 24 ++++----- frontend/src/views/FuelCodes/FuelCodes.jsx | 11 ++-- frontend/src/views/FuelCodes/_schema.jsx | 6 +-- .../views/FuelExports/AddEditFuelExports.jsx | 10 ++-- frontend/src/views/FuelExports/_schema.jsx | 16 +++--- .../FuelSupplies/AddEditFuelSupplies.jsx | 10 ++-- frontend/src/views/FuelSupplies/_schema.jsx | 12 ++--- .../AddEditNotionalTransfers.jsx | 6 +-- .../src/views/NotionalTransfers/_schema.jsx | 8 +-- .../Organizations/AddEditOrg/AddEditOrg.jsx | 54 +++++++++---------- .../src/views/OtherUses/AddEditOtherUses.jsx | 7 +-- frontend/src/views/OtherUses/_schema.jsx | 14 ++--- .../Transactions/AddEditViewTransaction.jsx | 14 ++--- .../Transactions/components/Comments.jsx | 5 +- .../Transactions/components/LabelBox.jsx | 4 +- .../components/OrgTransactionDetails.jsx | 23 ++++---- .../components/OrganizationList.jsx | 11 ++-- .../components/TransactionHistory.jsx | 10 ++-- .../views/Transfers/AddEditViewTransfer.jsx | 18 +++---- .../Transfers/components/AgreementDate.jsx | 7 ++- .../Transfers/components/AttachmentList.jsx | 12 +++-- .../Transfers/components/CommentList.jsx | 14 ++--- .../views/Transfers/components/LabelBox.jsx | 4 +- .../components/OrganizationBadge.jsx | 13 ++--- .../Transfers/components/Recommendation.jsx | 11 ++-- .../Transfers/components/SigningAuthority.jsx | 10 ++-- .../components/TransferDetailsCard.jsx | 11 ++-- .../Transfers/components/TransferGraphic.jsx | 18 +++---- .../Transfers/components/TransferHistory.jsx | 14 ++--- .../views/Users/AddEditUser/AddEditUser.jsx | 13 ++--- .../components/BCeIDSpecificRoleFields.jsx | 7 +-- .../components/IDIRSpecificRoleFields.jsx | 7 +-- 55 files changed, 351 insertions(+), 326 deletions(-) diff --git a/frontend/src/components/BCForm/BCFormCheckbox.jsx b/frontend/src/components/BCForm/BCFormCheckbox.jsx index 13f28a215..811a49e5c 100644 --- a/frontend/src/components/BCForm/BCFormCheckbox.jsx +++ b/frontend/src/components/BCForm/BCFormCheckbox.jsx @@ -2,9 +2,9 @@ import { Checkbox, FormControl, FormControlLabel, - FormLabel, - Typography + FormLabel } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { Controller } from 'react-hook-form' import { CustomLabel } from './CustomLabel' import PropTypes from 'prop-types' @@ -22,9 +22,9 @@ export const BCFormCheckbox = ({ name, form, label, options, disabled }) => { return ( - + {label} - +
diff --git a/frontend/src/components/BCForm/BCFormRadio.jsx b/frontend/src/components/BCForm/BCFormRadio.jsx index 215840d61..1854ae761 100644 --- a/frontend/src/components/BCForm/BCFormRadio.jsx +++ b/frontend/src/components/BCForm/BCFormRadio.jsx @@ -3,9 +3,9 @@ import { FormControlLabel, FormLabel, Radio, - RadioGroup, - Typography + RadioGroup } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { Controller } from 'react-hook-form' import PropTypes from 'prop-types' import { CustomLabel } from './CustomLabel' @@ -34,9 +34,9 @@ export const BCFormRadio = ({ name, control, label, options, disabled }) => { return ( - + {label} - + { @@ -14,14 +15,14 @@ export const BCFormText = ({ name, control, label, optional }) => { }) => ( <> - + {label}  {optional && ( (optional) )} - + ( - + {header} — {text} - + ) CustomLabel.propTypes = { diff --git a/frontend/src/components/BCTypography/BCTypographyRoot.jsx b/frontend/src/components/BCTypography/BCTypographyRoot.jsx index 605bcc6e9..b08b8ef3e 100644 --- a/frontend/src/components/BCTypography/BCTypographyRoot.jsx +++ b/frontend/src/components/BCTypography/BCTypographyRoot.jsx @@ -3,7 +3,7 @@ import Typography from '@mui/material/Typography' import { styled } from '@mui/material/styles' const BCTypographyRoot = styled(Typography)(({ theme, ownerState }) => { - const { palette, typography, functions } = theme + const { palette, typography, functions = {} } = theme const { color, textTransform, diff --git a/frontend/src/components/DisclaimerBanner.jsx b/frontend/src/components/DisclaimerBanner.jsx index fb0b2b87a..ac4e7e507 100644 --- a/frontend/src/components/DisclaimerBanner.jsx +++ b/frontend/src/components/DisclaimerBanner.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types' -import { Box, Typography } from '@mui/material' +import { Box } from '@mui/material' +import BCTypography from '@/components/BCTypography' import colors from '@/themes/base/colors' const DisclaimerBanner = ({ messages }) => { @@ -16,9 +17,9 @@ const DisclaimerBanner = ({ messages }) => { }} > {messages.map((message, index) => ( - + {message} - + ))} ) diff --git a/frontend/src/components/Loading.jsx b/frontend/src/components/Loading.jsx index 53575eac7..d1906365b 100644 --- a/frontend/src/components/Loading.jsx +++ b/frontend/src/components/Loading.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types' import CircularProgress from '@mui/material/CircularProgress' import Box from '@mui/material/Box' -import Typography from '@mui/material/Typography' +import BCTypography from '@/components/BCTypography' import colors from '@/themes/base/colors' import borders from '@/themes/base/borders' @@ -36,9 +36,9 @@ const Loading = ({ message = 'Loading...', fixed = false }) => { }} > - + {message} - + ) diff --git a/frontend/src/components/ProgressBreadcrumb.jsx b/frontend/src/components/ProgressBreadcrumb.jsx index 91743d589..c90d70988 100644 --- a/frontend/src/components/ProgressBreadcrumb.jsx +++ b/frontend/src/components/ProgressBreadcrumb.jsx @@ -1,6 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' -import { Breadcrumbs, Typography, Box, useMediaQuery } from '@mui/material' +import { Breadcrumbs, Box, useMediaQuery } from '@mui/material' +import BCTypography from '@/components/BCTypography' /** * ProgressBreadcrumb Component @@ -62,19 +63,19 @@ const ProgressBreadcrumb = ({ steps, currentStep }) => { mb: 1 }} > - {index + 1} - + - {step} - + ) } diff --git a/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx b/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx index 91f7bba1a..a6f994c90 100644 --- a/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx @@ -1,7 +1,7 @@ import { useRef, useCallback } from 'react' import BCBox from '@/components/BCBox' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { useTranslation } from 'react-i18next' import { auditLogColDefs, defaultAuditLogSortModel } from './_schema' import { apiRoutes, ROUTES } from '@/constants/routes' @@ -38,9 +38,9 @@ export const AuditLog = () => { return ( - + {t('admin:AuditLog')} - + { return ( - + {t('AuditLogDetails', { id })} - + {/* Display the additional information */} - + {t('auditLogColLabels.tableName')}: {tableName} - - + + {t('auditLogColLabels.operation')}: {operation} - - + + {t('auditLogColLabels.rowId')}: {rowId} - - + + {t('auditLogColLabels.createDate')}:{' '} {new Date(createDate).toLocaleString()} - - + + {t('auditLogColLabels.userId')}:{' '} {createUser || t('System')} - + diff --git a/frontend/src/views/AllocationAgreements/AddAllocationAgreements.jsx b/frontend/src/views/AllocationAgreements/AddAllocationAgreements.jsx index dd37955ad..7d3a50512 100644 --- a/frontend/src/views/AllocationAgreements/AddAllocationAgreements.jsx +++ b/frontend/src/views/AllocationAgreements/AddAllocationAgreements.jsx @@ -1,5 +1,5 @@ import { useState, useEffect, useMemo, useRef, useCallback } from 'react' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useTranslation } from 'react-i18next' import { useLocation, useNavigate, useParams } from 'react-router-dom' @@ -239,17 +239,17 @@ export const AddEditAllocationAgreements = () => { !allocationAgreementsLoading && (
- + {t('allocationAgreement:addAllocationAgreementRowsTitle')} - - + {t('allocationAgreement:allocationAgreementSubtitle')} - +
[ }, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellStyle: (params) => StandardCellErrors(params, errors), suppressKeyboardEvent, minWidth: 120, @@ -95,7 +95,7 @@ export const allocationAgreementColDefs = (optionsData, errors) => [ cellRenderer: (params) => params.value || (!params.value && ( - Enter or search a name + Enter or search a name )), cellStyle: (params) => StandardCellErrors(params, errors), suppressKeyboardEvent, @@ -177,7 +177,7 @@ export const allocationAgreementColDefs = (optionsData, errors) => [ }, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellStyle: (params) => StandardCellErrors(params, errors), suppressKeyboardEvent, minWidth: 200, @@ -276,7 +276,7 @@ export const allocationAgreementColDefs = (optionsData, errors) => [ }, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellStyle: (params) => StandardCellErrors(params, errors), suppressKeyboardEvent, minWidth: 300, diff --git a/frontend/src/views/ComplianceReports/ComplianceReports.jsx b/frontend/src/views/ComplianceReports/ComplianceReports.jsx index 75476cd50..973b6f46b 100644 --- a/frontend/src/views/ComplianceReports/ComplianceReports.jsx +++ b/frontend/src/views/ComplianceReports/ComplianceReports.jsx @@ -1,5 +1,5 @@ // mui components -import { Typography, Stack } from '@mui/material' +import { Stack } from '@mui/material' import BCBox from '@/components/BCBox' import BCAlert from '@/components/BCAlert' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' @@ -19,6 +19,7 @@ import { useCreateComplianceReport } from '@/hooks/useComplianceReports' // internal components import { reportsColDefs, defaultSortModel } from './components/_schema' import { NewComplianceReportButton } from './components/NewComplianceReportButton' +import BCTypography from '@/components/BCTypography' export const ComplianceReports = () => { const { t } = useTranslation(['common', 'report']) @@ -39,7 +40,10 @@ export const ComplianceReports = () => { }), [t] ) - const getRowId = useCallback((params) => params.data.complianceReportId.toString(), []) + const getRowId = useCallback( + (params) => params.data.complianceReportId.toString(), + [] + ) // eslint-disable-next-line react-hooks/exhaustive-deps const handleRowClicked = useCallback( ({ data }) => { @@ -114,9 +118,9 @@ export const ComplianceReports = () => { )}
- + {t('report:title')} - + { return ( <> - {t('report:errorRetrieving')} + {t('report:errorRetrieving')} ) } @@ -180,22 +181,22 @@ export const EditViewComplianceReport = () => { data={modalData} /> - {compliancePeriod + ' ' + t('report:complianceReport')} -{' '} {reportData?.report.nickname} - - + Status: {currentStatus} - + @@ -242,9 +243,9 @@ export const EditViewComplianceReport = () => { {/* Internal Comments */} {isGovernmentUser && ( - + {t(`report:internalComments`)} - + { gap: 2 }} > - { }} /> - + {t('report:activityLinksList')}: - + - {t('report:uploadLabel')} - + - + {orgData?.name} - + @@ -190,7 +190,7 @@ export const AssessmentCard = ({ {!isGovernmentUser && ( - - {t('report:renewableFuelTarget')} - + @@ -223,13 +223,13 @@ export const AssessmentCard = ({ - {t('report:lowCarbonFuelTargetSummary')} - + @@ -248,14 +248,14 @@ export const AssessmentCard = ({ )} {!!chain.length && ( <> - {t('report:reportHistory')} - + {chain.map((report) => ( ))} @@ -266,13 +266,13 @@ export const AssessmentCard = ({ {isFeatureEnabled(FEATURE_FLAGS.SUPPLEMENTAL_REPORTING) && currentStatus === COMPLIANCE_REPORT_STATUSES.ASSESSED && ( <> - {t('report:supplementalWarning')} - + {t('report:errorRetrieving')} + return {t('report:errorRetrieving')} } return ( <> - + {t('report:summaryAndDeclaration')} - + } diff --git a/frontend/src/views/ComplianceReports/components/Introduction.jsx b/frontend/src/views/ComplianceReports/components/Introduction.jsx index 2a804dc96..ec3747941 100644 --- a/frontend/src/views/ComplianceReports/components/Introduction.jsx +++ b/frontend/src/views/ComplianceReports/components/Introduction.jsx @@ -3,22 +3,22 @@ import { Accordion, AccordionDetails, AccordionSummary, - Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { GlobalStyles } from '@mui/system' import { useTranslation } from 'react-i18next' // Reusable Section Component const Section = ({ header, content }) => ( <> - + > {content.map((paragraph, index) => ( - ( } }} dangerouslySetInnerHTML={{ __html: paragraph }} - > + > ))} ) @@ -58,9 +58,9 @@ export const Introduction = ({ expanded, compliancePeriod }) => { id="compliance-report-intro" data-test="compliance-report-intro" > - + {t('report:introduction')} - + {/* Render each section using map */} @@ -69,10 +69,10 @@ export const Introduction = ({ expanded, compliancePeriod }) => { ))} - + {t('report:questions')} - - + { } }} dangerouslySetInnerHTML={{ __html: t('report:contact') }} - > + > ) } diff --git a/frontend/src/views/ComplianceReports/components/OrgDetailsCard.jsx b/frontend/src/views/ComplianceReports/components/OrgDetailsCard.jsx index fde2af7a1..c2c990dd7 100644 --- a/frontend/src/views/ComplianceReports/components/OrgDetailsCard.jsx +++ b/frontend/src/views/ComplianceReports/components/OrgDetailsCard.jsx @@ -1,5 +1,6 @@ import { useTranslation } from 'react-i18next' -import { Stack, Typography } from '@mui/material' +import { Stack } from '@mui/material' +import BCTypography from '@/components/BCTypography' import BCWidgetCard from '@/components/BCWidgetCard/BCWidgetCard' import { constructAddress } from '@/utils/constructAddress' @@ -12,24 +13,24 @@ export const OrgDetailsCard = ({ orgName, orgAddress, orgAttorneyAddress, isGove title={t('report:orgDetails')} content={ - + {orgName} - +
- + {t('report:serviceAddrLabel')}: - {' '} - + {' '} + {orgAddress && constructAddress(orgAddress)} - +
- {t('report:bcAddrLabel')}:{' '} - + {t('report:bcAddrLabel')}:{' '} + {orgAttorneyAddress && constructAddress(orgAttorneyAddress)} - +
- {!isGovernmentUser && { return ( <> - + {t('report:reportDetails')} { > {t('report:collapseAll')} - + {activityList.map((activity, index) => { const { data, error, isLoading } = activity.useFetch(complianceReportId) return ( @@ -223,7 +223,7 @@ const ReportDetails = ({ currentStatus = 'Draft' }) => { id={`panel${index}-header`} data-test={`panel${index}-summary`} > - {
)} - + {isLoading ? ( ) : error ? ( - Error loading data + Error loading data ) : activity.component ? ( activity.component(data) ) : ( - {JSON.stringify(data)} + {JSON.stringify(data)} )} diff --git a/frontend/src/views/FinalSupplyEquipments/AddEditFinalSupplyEquipments.jsx b/frontend/src/views/FinalSupplyEquipments/AddEditFinalSupplyEquipments.jsx index fbfa3ceb3..fb9fcafaa 100644 --- a/frontend/src/views/FinalSupplyEquipments/AddEditFinalSupplyEquipments.jsx +++ b/frontend/src/views/FinalSupplyEquipments/AddEditFinalSupplyEquipments.jsx @@ -1,5 +1,5 @@ import { useState, useEffect, useMemo, useRef, useCallback } from 'react' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useTranslation } from 'react-i18next' import { useLocation, useNavigate, useParams } from 'react-router-dom' @@ -262,17 +262,17 @@ export const AddEditFinalSupplyEquipments = () => { !equipmentsLoading && (
- + {t('finalSupplyEquipment:addFSErowsTitle')} - - + {t('finalSupplyEquipment:fseSubtitle')} - +
( - + {params.value[0] ? `${params.value[0]} to ${params.value[1]}` : 'YYYY-MM-DD to YYYY-MM-DD'} - + ), suppressKeyboardEvent, cellStyle: (params) => StandardCellErrors(params, errors), @@ -162,7 +162,7 @@ export const finalSupplyEquipmentColDefs = ( cellStyle: (params) => StandardCellErrors(params, errors), cellRenderer: (params) => params.value || - (!params.value && Select) + (!params.value && Select) }, { field: 'ports', @@ -183,7 +183,7 @@ export const finalSupplyEquipmentColDefs = ( cellStyle: (params) => StandardCellErrors(params, errors), cellRenderer: (params) => params.value || - (!params.value && Select) + (!params.value && Select) }, { field: 'fuelMeasurementType', @@ -204,7 +204,7 @@ export const finalSupplyEquipmentColDefs = ( cellStyle: (params) => StandardCellErrors(params, errors), cellRenderer: (params) => params.value || - (!params.value && Select) + (!params.value && Select) }, { field: 'intendedUses', @@ -224,7 +224,7 @@ export const finalSupplyEquipmentColDefs = ( (params.value && params.value !== '' && ( )) || - (!params.value && Select), + (!params.value && Select), suppressKeyboardEvent, minWidth: 560 }, @@ -246,7 +246,7 @@ export const finalSupplyEquipmentColDefs = ( (params.value && params.value !== '' && ( )) || - (!params.value && Select), + (!params.value && Select), suppressKeyboardEvent, minWidth: 315 }, diff --git a/frontend/src/views/FuelCodes/AddFuelCode/AddEditFuelCode.jsx b/frontend/src/views/FuelCodes/AddFuelCode/AddEditFuelCode.jsx index 044c767a7..1b5d6448c 100644 --- a/frontend/src/views/FuelCodes/AddFuelCode/AddEditFuelCode.jsx +++ b/frontend/src/views/FuelCodes/AddFuelCode/AddEditFuelCode.jsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { Stack, Typography } from '@mui/material' +import { Stack } from '@mui/material' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { v4 as uuid } from 'uuid' import { BCGridEditor } from '@/components/BCDataGrid/BCGridEditor' @@ -307,13 +307,13 @@ const AddEditFuelCodeBase = () => { <>
- + {!existingFuelCode && t('fuelCode:newFuelCodeTitle')} {existingFuelCode?.fuelCodeStatus.status === FUEL_CODE_STATUSES.DRAFT && t('fuelCode:editFuelCodeTitle')} {existingFuelCode?.fuelCodeStatus.status === FUEL_CODE_STATUSES.APPROVED && t('fuelCode:viewFuelCodeTitle')} - +
{ } onClick={handleOpenApprovalModal} > - + {t('fuelCode:approveFuelCodeBtn')} - +
)} diff --git a/frontend/src/views/FuelCodes/AddFuelCode/_schema.jsx b/frontend/src/views/FuelCodes/AddFuelCode/_schema.jsx index 3c39a6f4c..e42f2b8c7 100644 --- a/frontend/src/views/FuelCodes/AddFuelCode/_schema.jsx +++ b/frontend/src/views/FuelCodes/AddFuelCode/_schema.jsx @@ -9,7 +9,7 @@ import { import { apiRoutes } from '@/constants/routes' import i18n from '@/i18n' import { CommonArrayRenderer } from '@/utils/grid/cellRenderers' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { actions, validation } from '@/components/BCDataGrid/columns' import { numberFormatter } from '@/utils/formatters' @@ -30,7 +30,7 @@ const createCellRenderer = (field, customRenderer = null) => { const content = customRenderer ? customRenderer(params) : params.value || - (!params.value && Select) + (!params.value && Select) return
{content}
} @@ -257,9 +257,9 @@ export const fuelCodeColDefs = (optionsData, errors, isCreate, canEdit) => [ maxWidth: 220, minWidth: 200, cellRenderer: createCellRenderer('applicationDate', (params) => ( - + {params.value ? params.value : 'YYYY-MM-DD'} - + )), suppressKeyboardEvent, cellEditor: DateEditor @@ -272,9 +272,9 @@ export const fuelCodeColDefs = (optionsData, errors, isCreate, canEdit) => [ maxWidth: 220, minWidth: 220, cellRenderer: createCellRenderer('approvalDate', (params) => ( - + {params.value ? params.value : 'YYYY-MM-DD'} - + )), suppressKeyboardEvent, @@ -288,9 +288,9 @@ export const fuelCodeColDefs = (optionsData, errors, isCreate, canEdit) => [ maxWidth: 220, minWidth: 220, cellRenderer: createCellRenderer('effectiveDate', (params) => ( - + {params.value ? params.value : 'YYYY-MM-DD'} - + )), suppressKeyboardEvent, cellEditor: DateEditor @@ -303,9 +303,9 @@ export const fuelCodeColDefs = (optionsData, errors, isCreate, canEdit) => [ maxWidth: 220, minWidth: 220, cellRenderer: createCellRenderer('expirationDate', (params) => ( - + {params.value ? params.value : 'YYYY-MM-DD'} - + )), suppressKeyboardEvent, cellEditor: DateEditor @@ -561,7 +561,7 @@ export const fuelCodeColDefs = (optionsData, errors, isCreate, canEdit) => [ params.value && params.value.length > 0 ? ( ) : ( - Select + Select ) ), cellRendererParams: { @@ -586,7 +586,7 @@ export const fuelCodeColDefs = (optionsData, errors, isCreate, canEdit) => [ params.value && params.value.length > 0 ? ( ) : ( - Select + Select ) ), cellRendererParams: { diff --git a/frontend/src/views/FuelCodes/FuelCodes.jsx b/frontend/src/views/FuelCodes/FuelCodes.jsx index 094ee425d..fba322f9a 100644 --- a/frontend/src/views/FuelCodes/FuelCodes.jsx +++ b/frontend/src/views/FuelCodes/FuelCodes.jsx @@ -11,7 +11,8 @@ import { useApiService } from '@/services/useApiService' import withRole from '@/utils/withRole' import { faCirclePlus } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { Stack, Typography } from '@mui/material' +import { Stack } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -68,9 +69,9 @@ const FuelCodesBase = () => { )} - + {t('FuelCodes')} - + { data-test="new-fuel-code-btn" onClick={() => navigate(ROUTES.FUELCODES_ADD)} > - + {t('fuelCode:newFuelCodeBtn')} - + [ filter: false, headerName: t('fuelCode:fuelCodeColLabels.lastUpdated'), cellRenderer: (params) => ( - + {params.value ? timezoneFormatter({ value: params.value }) : 'YYYY-MM-DD'} - + ), minWidth: 300 }, diff --git a/frontend/src/views/FuelExports/AddEditFuelExports.jsx b/frontend/src/views/FuelExports/AddEditFuelExports.jsx index 5e6a3cf76..ebaa03498 100644 --- a/frontend/src/views/FuelExports/AddEditFuelExports.jsx +++ b/frontend/src/views/FuelExports/AddEditFuelExports.jsx @@ -7,7 +7,7 @@ import { useSaveFuelExport } from '@/hooks/useFuelExport' import { isArrayEmpty } from '@/utils/formatters' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -228,17 +228,17 @@ export const AddEditFuelExports = () => { !fuelExportsLoading && (
- + {t('fuelExport:addFuelExportRowsTitle')} - - + {t('fuelExport:fuelExportSubtitle')} - +
[ maxWidth: 220, minWidth: 200, cellRenderer: (params) => ( - + {params.value ? params.value : 'YYYY-MM-DD'} - + ), suppressKeyboardEvent, cellEditor: DateEditor, @@ -112,7 +112,7 @@ export const fuelExportColDefs = (optionsData, errors) => [ cellEditor: AutocompleteCellEditor, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellEditorParams: { options: optionsData?.fuelTypes?.map((obj) => obj.fuelType).sort(), multiple: false, @@ -181,7 +181,7 @@ export const fuelExportColDefs = (optionsData, errors) => [ cellEditor: AutocompleteCellEditor, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellEditorParams: (params) => ({ options: optionsData?.fuelTypes ?.find((obj) => params.data.fuelType === obj.fuelType) @@ -255,7 +255,7 @@ export const fuelExportColDefs = (optionsData, errors) => [ cellEditor: AutocompleteCellEditor, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellStyle: (params) => cellErrorStyle(params, errors), suppressKeyboardEvent, valueGetter: (params) => { @@ -288,7 +288,7 @@ export const fuelExportColDefs = (optionsData, errors) => [ cellEditor: 'agSelectCellEditor', cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellEditorParams: (params) => ({ values: optionsData?.fuelTypes ?.find((obj) => params.data.fuelType === obj.fuelType) @@ -370,7 +370,7 @@ export const fuelExportColDefs = (optionsData, errors) => [ }), cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), suppressKeyboardEvent, editable: (params) => isFuelTypeOther(params), cellStyle: (params) => { diff --git a/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx b/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx index f5e3b6506..a6289c0d7 100644 --- a/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx +++ b/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx @@ -8,7 +8,7 @@ import { useSaveFuelSupply } from '@/hooks/useFuelSupply' import { isArrayEmpty } from '@/utils/formatters' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -267,17 +267,17 @@ export const AddEditFuelSupplies = () => { !fuelSuppliesLoading && (
- + {t('fuelSupply:addFuelSupplyRowsTitle')} - - + {t('fuelSupply:fuelSupplySubtitle')} - +
[ cellEditor: AutocompleteCellEditor, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellEditorParams: { options: optionsData?.fuelTypes?.map((obj) => obj.fuelType).sort(), multiple: false, @@ -150,7 +150,7 @@ export const fuelSupplyColDefs = (optionsData, errors, warnings) => [ cellEditor: AutocompleteCellEditor, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellEditorParams: (params) => ({ options: optionsData?.fuelTypes ?.find((obj) => params.data.fuelType === obj.fuelType) @@ -223,7 +223,7 @@ export const fuelSupplyColDefs = (optionsData, errors, warnings) => [ cellEditor: AutocompleteCellEditor, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellStyle: (params) => StandardCellWarningAndErrors(params, errors, warnings), suppressKeyboardEvent, @@ -260,7 +260,7 @@ export const fuelSupplyColDefs = (optionsData, errors, warnings) => [ cellEditor: 'agSelectCellEditor', cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellEditorParams: (params) => ({ values: optionsData?.fuelTypes ?.find((obj) => params.data.fuelType === obj.fuelType) @@ -369,7 +369,7 @@ export const fuelSupplyColDefs = (optionsData, errors, warnings) => [ }), cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), suppressKeyboardEvent, editable: (params) => isFuelTypeOther(params), cellStyle: (params) => diff --git a/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx b/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx index dae931de3..2360dfb19 100644 --- a/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx +++ b/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx @@ -1,5 +1,5 @@ import { useState, useEffect, useMemo, useRef, useCallback } from 'react' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useTranslation } from 'react-i18next' import { useLocation, useNavigate, useParams } from 'react-router-dom' @@ -201,9 +201,9 @@ export const AddEditNotionalTransfers = () => { !transfersLoading && (
- + {t('notionalTransfer:newNotionalTransferTitle')} - +
[ cellRenderer: (params) => params.value || (!params.value && ( - Enter or search a name + Enter or search a name )), suppressKeyboardEvent, minWidth: 300, @@ -107,7 +107,7 @@ export const notionalTransferColDefs = (optionsData, errors) => [ cellStyle: (params) => StandardCellErrors(params, errors), cellRenderer: (params) => params.value || - (!params.value && Select) + (!params.value && Select) }, { field: 'receivedOrTransferred', @@ -128,7 +128,7 @@ export const notionalTransferColDefs = (optionsData, errors) => [ cellStyle: (params) => StandardCellErrors(params, errors), cellRenderer: (params) => params.value || - (!params.value && Select) + (!params.value && Select) }, { field: 'quantity', diff --git a/frontend/src/views/Organizations/AddEditOrg/AddEditOrg.jsx b/frontend/src/views/Organizations/AddEditOrg/AddEditOrg.jsx index db41edc62..829ce2114 100644 --- a/frontend/src/views/Organizations/AddEditOrg/AddEditOrg.jsx +++ b/frontend/src/views/Organizations/AddEditOrg/AddEditOrg.jsx @@ -13,9 +13,9 @@ import { Paper, Radio, RadioGroup, - TextField, - Typography + TextField } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { useMutation } from '@tanstack/react-query' import { useCallback, useEffect, useState } from 'react' import { useForm, Controller } from 'react-hook-form' @@ -136,9 +136,9 @@ export const AddEditOrg = () => { } return ( errors[fieldName] && ( - + {errors[fieldName].message} - + ) ) } @@ -301,9 +301,9 @@ export const AddEditOrg = () => { {t('common:submitError')} )} - + {orgID ? t('org:editOrgTitle') : t('org:addOrgTitle')} - + { /> } label={ - + {t('org:sameAsLegalNameLabel')} - + } /> @@ -413,9 +413,9 @@ export const AddEditOrg = () => { - + {t('org:supplierTypLabel')}: - + @@ -435,9 +435,9 @@ export const AddEditOrg = () => { /> } label={ - + {t('supplier')} - + } /> @@ -451,9 +451,9 @@ export const AddEditOrg = () => { - + {t('org:regTrnLabel')}: - + @@ -474,9 +474,9 @@ export const AddEditOrg = () => { } label={ - + {t('yes')} - + } /> { } label={ - + {t('no')} - + } /> @@ -522,9 +522,9 @@ export const AddEditOrg = () => { - + {t('org:serviceAddrLabel')} - + {t('org:streetAddrLabel')}: @@ -612,9 +612,9 @@ export const AddEditOrg = () => { - + {t('org:bcAddrLabel')} - + { /> } label={ - + {t('org:sameAddrLabel')} - + } /> @@ -762,9 +762,9 @@ export const AddEditOrg = () => { } onClick={() => navigate(ROUTES.ORGANIZATIONS)} > - + {t('backBtn')} - + { } > - {t('saveBtn')} + {t('saveBtn')} diff --git a/frontend/src/views/OtherUses/AddEditOtherUses.jsx b/frontend/src/views/OtherUses/AddEditOtherUses.jsx index 6de1e3a21..58586cb9e 100644 --- a/frontend/src/views/OtherUses/AddEditOtherUses.jsx +++ b/frontend/src/views/OtherUses/AddEditOtherUses.jsx @@ -10,7 +10,8 @@ import { import { cleanEmptyStringValues } from '@/utils/formatters' import { faFloppyDisk } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { Stack, Typography } from '@mui/material' +import { Stack } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -233,9 +234,9 @@ export const AddEditOtherUses = () => { isFetched && (
- + {t('otherUses:newOtherUsesTitle')} - +
[ }, suppressKeyboardEvent, cellRenderer: (params) => - params.value || Select, + params.value || Select, cellStyle: (params) => StandardCellErrors(params, errors) }, { @@ -58,7 +58,7 @@ export const otherUsesColDefs = (optionsData, errors) => [ }, suppressKeyboardEvent, cellRenderer: (params) => - params.value || Select, + params.value || Select, cellStyle: (params) => StandardCellErrors(params, errors), minWidth: 200 }, @@ -84,7 +84,7 @@ export const otherUsesColDefs = (optionsData, errors) => [ }, cellRenderer: (params) => params.value || - (!params.value && Select), + (!params.value && Select), cellStyle: (params) => StandardCellErrors(params, errors), suppressKeyboardEvent, valueSetter: (params) => { @@ -121,7 +121,7 @@ export const otherUsesColDefs = (optionsData, errors) => [ params.data.provisionOfTheAct === PROVISION_APPROVED_FUEL_CODE && fuelType?.fuelCodes?.length > 0 ) { - return params.value || Select; + return params.value || Select; } return null; }, @@ -193,7 +193,7 @@ export const otherUsesColDefs = (optionsData, errors) => [ }, suppressKeyboardEvent, cellRenderer: (params) => - params.value || Select, + params.value || Select, cellStyle: (params) => StandardCellErrors(params, errors) }, { @@ -246,7 +246,7 @@ export const otherUsesColDefs = (optionsData, errors) => [ }, suppressKeyboardEvent, cellRenderer: (params) => - params.value || Select, + params.value || Select, cellStyle: (params) => StandardCellErrors(params, errors), minWidth: 200 }, diff --git a/frontend/src/views/Transactions/AddEditViewTransaction.jsx b/frontend/src/views/Transactions/AddEditViewTransaction.jsx index 0470f3797..766559a92 100644 --- a/frontend/src/views/Transactions/AddEditViewTransaction.jsx +++ b/frontend/src/views/Transactions/AddEditViewTransaction.jsx @@ -23,12 +23,12 @@ import { import { useTheme, Stack, - Typography, useMediaQuery, Step, StepLabel, Stepper } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faArrowLeft } from '@fortawesome/free-solid-svg-icons' import BCBox from '@/components/BCBox' @@ -345,9 +345,9 @@ export const AddEditViewTransaction = () => { /> {/* Header section */} - + {title} - + {/* Progress bar */} { {/* Internal Comments */} - + {t(`txn:internalCommentsOptional`)} - + { onClick={() => navigate(ROUTES.TRANSACTIONS)} > - + {t('backBtn')} - + {buttonClusterConfig[ transactionId ? currentStatus : TRANSACTION_STATUSES.NEW diff --git a/frontend/src/views/Transactions/components/Comments.jsx b/frontend/src/views/Transactions/components/Comments.jsx index a630c7533..52de50b7e 100644 --- a/frontend/src/views/Transactions/components/Comments.jsx +++ b/frontend/src/views/Transactions/components/Comments.jsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react' -import { Box, Typography, Collapse, IconButton, TextField } from '@mui/material' +import { Box, Collapse, IconButton, TextField } from '@mui/material' +import BCTypography from '@/components/BCTypography' import ExpandLessIcon from '@mui/icons-material/ExpandLess' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import { useFormContext } from 'react-hook-form' @@ -37,7 +38,7 @@ export const Comments = ({ commentField, isEditable }) => { onClick={handleToggle} sx={{ cursor: 'pointer' }} > - {t('txn:commentsDescText')} + {t('txn:commentsDescText')} {isExpanded ? : } diff --git a/frontend/src/views/Transactions/components/LabelBox.jsx b/frontend/src/views/Transactions/components/LabelBox.jsx index a5e837539..5fa29ae1d 100644 --- a/frontend/src/views/Transactions/components/LabelBox.jsx +++ b/frontend/src/views/Transactions/components/LabelBox.jsx @@ -28,9 +28,9 @@ export const LabelBox = ({ > {description && ( - + {description} - + )} {children} diff --git a/frontend/src/views/Transactions/components/OrgTransactionDetails.jsx b/frontend/src/views/Transactions/components/OrgTransactionDetails.jsx index b25fb2e1f..b48ea7897 100644 --- a/frontend/src/views/Transactions/components/OrgTransactionDetails.jsx +++ b/frontend/src/views/Transactions/components/OrgTransactionDetails.jsx @@ -1,5 +1,6 @@ import React from 'react' -import { Box, Grid, Typography } from '@mui/material' +import { Box, Grid } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { useTranslation } from 'react-i18next' import { dateFormatter, numberFormatter } from '@/utils/formatters' import BCWidgetCard from '@/components/BCWidgetCard/BCWidgetCard' @@ -33,32 +34,32 @@ export const OrgTransactionDetails = ({ transactionType, transactionData }) => { // Construct the content based on the transaction type const content = ( - + {transactionType === ADMIN_ADJUSTMENT ? t('txn:administrativeAdjustment') : t('txn:initiativeAgreement')}{' '} {t('txn:for')} {transactionData.toOrganization.name} - - + + {t('txn:complianceUnitsLabel')}{' '} {numberFormatter({ value: transactionData.complianceUnits })} - - + + {t('txn:effectiveDateLabel')}{' '} {dateFormatter({ value: effectiveDate })} - + {transactionData.govComment && ( - + {t('txn:commentsTextLabel')}{' '} {transactionData.govComment} - + )} - + {t('txn:approvedLabel')}{' '} {dateFormatter({ value: approvedDate })} {t('txn:approvedByDirector')} - + ) diff --git a/frontend/src/views/Transactions/components/OrganizationList.jsx b/frontend/src/views/Transactions/components/OrganizationList.jsx index e2f9719dd..1bc750edb 100644 --- a/frontend/src/views/Transactions/components/OrganizationList.jsx +++ b/frontend/src/views/Transactions/components/OrganizationList.jsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react' import PropTypes from 'prop-types' -import { Box, Stack, Typography, Autocomplete, TextField } from '@mui/material' +import { Box, Stack, Autocomplete, TextField } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { useTranslation } from 'react-i18next' import { useOrganizationNames } from '@/hooks/useOrganizations' import { numberFormatter } from '@/utils/formatters' @@ -47,9 +48,9 @@ const OrganizationList = ({ onOrgChange }) => { return ( - + {org} - + { useFlexGap flexWrap="wrap" > - + {t('txn:showTransactionsInvolve')}:  - + { return ( - + {t('txn:txnHistoryLabel')} - +
    {transactionHistory?.map((item, index) => (
  • - + {getTransactionStatusLabel(getStatusObject(item))} @@ -50,7 +50,7 @@ export const TransactionHistory = ({ transactionHistory }) => { of {t('govOrg')} - +
  • ))}
diff --git a/frontend/src/views/Transfers/AddEditViewTransfer.jsx b/frontend/src/views/Transfers/AddEditViewTransfer.jsx index 6e15fd993..2968b16a8 100644 --- a/frontend/src/views/Transfers/AddEditViewTransfer.jsx +++ b/frontend/src/views/Transfers/AddEditViewTransfer.jsx @@ -23,10 +23,10 @@ import { Step, StepLabel, Stepper, - Typography, useMediaQuery, useTheme } from '@mui/material' +import BCTypography from '@/components/BCTypography' import BCAlert from '@/components/BCAlert' import BCBox from '@/components/BCBox' import BCButton from '@/components/BCButton' @@ -365,18 +365,18 @@ export const AddEditViewTransfer = () => { /> {/* Header section */} - + {title} - + {transferStatus !== TRANSFER_STATUSES.RECORDED && ( - + {t('transfer:effectiveText')} - +
- + {t('transfer:considerationText')} - +
)} {/* Progress bar */} @@ -470,12 +470,12 @@ export const AddEditViewTransfer = () => { onClick={() => navigate(ROUTES.TRANSACTIONS)} > - {t('backBtn')} - + {buttonClusterConfig[transferId ? currentStatus : 'New']?.map( (config) => diff --git a/frontend/src/views/Transfers/components/AgreementDate.jsx b/frontend/src/views/Transfers/components/AgreementDate.jsx index c05887356..10effa986 100644 --- a/frontend/src/views/Transfers/components/AgreementDate.jsx +++ b/frontend/src/views/Transfers/components/AgreementDate.jsx @@ -1,4 +1,5 @@ -import { Box, TextField, Typography } from '@mui/material' +import { Box, TextField } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { useFormContext } from 'react-hook-form' import { LabelBox } from './LabelBox' import { useTranslation } from 'react-i18next' @@ -25,7 +26,9 @@ export const AgreementDate = () => { justifyContent="flex-start" gap="10px" > - {t('transfer:agrDateHeader')} + + {t('transfer:agrDateHeader')} + { return ( - + Attachments - + {attachments.map((attachment) => ( { key={attachment.attachmentID} alignItems="flex-start" > - + ({ diff --git a/frontend/src/views/Transfers/components/CommentList.jsx b/frontend/src/views/Transfers/components/CommentList.jsx index 8d7e135e3..33b88cf1a 100644 --- a/frontend/src/views/Transfers/components/CommentList.jsx +++ b/frontend/src/views/Transfers/components/CommentList.jsx @@ -1,7 +1,6 @@ import BCBox from '@/components/BCBox' import PropTypes from 'prop-types' import { - Typography, List, ListItem, ListItemAvatar, @@ -9,12 +8,13 @@ import { Avatar, Divider } from '@mui/material' +import BCTypography from '@/components/BCTypography' export const CommentList = ({ comments = [] }) => ( - + Comments - + ( - ( > {comment.name} {':'} - + } secondary={ <> - {comment.comment} - + } /> diff --git a/frontend/src/views/Transfers/components/LabelBox.jsx b/frontend/src/views/Transfers/components/LabelBox.jsx index a5e837539..5fa29ae1d 100644 --- a/frontend/src/views/Transfers/components/LabelBox.jsx +++ b/frontend/src/views/Transfers/components/LabelBox.jsx @@ -28,9 +28,9 @@ export const LabelBox = ({ > {description && ( - + {description} - + )} {children} diff --git a/frontend/src/views/Transfers/components/OrganizationBadge.jsx b/frontend/src/views/Transfers/components/OrganizationBadge.jsx index 132debc01..6ddeaee2a 100644 --- a/frontend/src/views/Transfers/components/OrganizationBadge.jsx +++ b/frontend/src/views/Transfers/components/OrganizationBadge.jsx @@ -1,6 +1,7 @@ import { PropTypes } from 'prop-types' import BCBadge from '@/components/BCBadge' -import { Stack, Typography } from '@mui/material' +import { Stack } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { Role } from '@/components/Role' import { roles } from '@/constants/roles' import { useOrganizationBalance } from '@/hooks/useOrganization' @@ -23,16 +24,16 @@ export const OrganizationBadge = ({ badgeContent={ <> - {organizationName} + {organizationName} {['Submitted', 'Recommended'].includes(transferStatus) && ( - + Balance: {orgInfo?.totalBalance.toLocaleString()} ( {Math.abs(orgInfo?.reservedBalance).toLocaleString()}) - - + + Registered: {orgInfo?.registered ? 'Yes' : 'No'} - + )} diff --git a/frontend/src/views/Transfers/components/Recommendation.jsx b/frontend/src/views/Transfers/components/Recommendation.jsx index 100568e89..aedaaf7da 100644 --- a/frontend/src/views/Transfers/components/Recommendation.jsx +++ b/frontend/src/views/Transfers/components/Recommendation.jsx @@ -1,7 +1,8 @@ import BCBox from '@/components/BCBox' import { TRANSFER_STATUSES } from '@/constants/statuses' import { useTransfer } from '@/hooks/useTransfer' -import { FormControlLabel, Radio, RadioGroup, Typography } from '@mui/material' +import { FormControlLabel, Radio, RadioGroup } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { Controller, useFormContext } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' @@ -18,9 +19,9 @@ export const Recommendation = ({ currentStatus }) => { return ( - + {t('transfer:analystRecommend')} - + {transferData.currentStatus.status === TRANSFER_STATUSES.SUBMITTED ? ( { )} /> ) : ( - + The analyst has recommended that you to{' '} {transferData.recommendation} this transfer. - + )} ) diff --git a/frontend/src/views/Transfers/components/SigningAuthority.jsx b/frontend/src/views/Transfers/components/SigningAuthority.jsx index 910a6cdd0..2d734a2b5 100644 --- a/frontend/src/views/Transfers/components/SigningAuthority.jsx +++ b/frontend/src/views/Transfers/components/SigningAuthority.jsx @@ -1,4 +1,4 @@ -import { Box, FormControlLabel, Checkbox, Typography } from '@mui/material' +import { Box, FormControlLabel, Checkbox } from '@mui/material' import BCTypography from '@/components/BCTypography' import withRole from '@/utils/withRole' import { useFormContext } from 'react-hook-form' @@ -34,15 +34,15 @@ export const SigningAuthority = () => { /> } label={ - + {t('transfer:saConfirmation')} - + } /> {errors.signingAuthorityDeclaration && ( - + {errors.signingAuthorityDeclaration.message} - + )}
diff --git a/frontend/src/views/Transfers/components/TransferDetailsCard.jsx b/frontend/src/views/Transfers/components/TransferDetailsCard.jsx index 4e45cfb45..b215cef39 100644 --- a/frontend/src/views/Transfers/components/TransferDetailsCard.jsx +++ b/frontend/src/views/Transfers/components/TransferDetailsCard.jsx @@ -1,7 +1,8 @@ import PropTypes from 'prop-types' import SyncAltIcon from '@mui/icons-material/SyncAlt' import SwapVertIcon from '@mui/icons-material/SwapVert' -import { Stack, Typography, useMediaQuery, useTheme } from '@mui/material' +import { Stack, useMediaQuery, useTheme } from '@mui/material' +import BCTypography from '@/components/BCTypography' import BCBox from '@/components/BCBox' import { OrganizationBadge } from '@/views/Transfers/components' import { useTranslation } from 'react-i18next' @@ -42,11 +43,11 @@ export const TransferDetailsCard = ({ transferStatus={transferStatus} /> - + {isMobileSize ? `$${decimalFormatter(totalValue)}` : `${quantity} ${t('transfer:complianceUnits')}`} - + )} - + {!isMobileSize ? `$${decimalFormatter(totalValue)}` : `${quantity} ${t('transfer:complianceUnits')}`} - + { )?.name || '' const pricePerUnit = parseFloat(watch('pricePerUnit')) - const totalValue = - quantity && pricePerUnit ? quantity * pricePerUnit : 0 + const totalValue = quantity && pricePerUnit ? quantity * pricePerUnit : 0 const isNumberOfCreditsValid = (number) => !isNaN(number) && number > 0 const isTotalValueValid = (value) => typeof value === 'number' && value > 0 @@ -99,7 +99,7 @@ export const TransferGraphic = () => { overflow: 'hidden' }} > - {creditsFrom} + {creditsFrom} { }} > {isNumberOfCreditsValid(quantity) && ( - + {`${formattedNumberOfCredits} compliance units`} - + )} {renderIcon()} {isTotalValueValid(totalValue) && ( - + {formatCurrency(totalValue)} - + )} @@ -145,7 +145,7 @@ export const TransferGraphic = () => { justifyContent: 'center' }} > - {creditsTo || ''} + {creditsTo || ''}
) diff --git a/frontend/src/views/Transfers/components/TransferHistory.jsx b/frontend/src/views/Transfers/components/TransferHistory.jsx index f6be941ef..b4f50bf17 100644 --- a/frontend/src/views/Transfers/components/TransferHistory.jsx +++ b/frontend/src/views/Transfers/components/TransferHistory.jsx @@ -4,7 +4,7 @@ import { TRANSFER_RECOMMENDATION } from '@/constants/statuses' import { useTransfer } from '@/hooks/useTransfer' -import { Typography } from '@mui/material' +import BCTypography from '@/components/BCTypography' import dayjs from 'dayjs' import localizedFormat from 'dayjs/plugin/localizedFormat' import duration from 'dayjs/plugin/duration' @@ -65,9 +65,9 @@ function TransferHistory({ transferHistory }) { return ( - + {t('transfer:txnHistory')} - +
    {[ @@ -78,7 +78,7 @@ function TransferHistory({ transferHistory }) { ].includes(currentStatus) && agreementDate && (
  • - + Date of written agreement reached between the two organizations: {agreementDate.format('LL')} (proposal falls @@ -101,12 +101,12 @@ function TransferHistory({ transferHistory }) { )} ) - +
  • )} {transferHistory?.map((item, index) => (
  • - + {getTransferStatusLabel(item.transferStatus?.status)}{' '} on {dayjs(item.createDate).format('LL')} @@ -122,7 +122,7 @@ function TransferHistory({ transferHistory }) { ? item.userProfile.organization.name : t('govOrg')}{' '} - +
  • ))}
diff --git a/frontend/src/views/Users/AddEditUser/AddEditUser.jsx b/frontend/src/views/Users/AddEditUser/AddEditUser.jsx index 18b129042..bcb3db66b 100644 --- a/frontend/src/views/Users/AddEditUser/AddEditUser.jsx +++ b/frontend/src/views/Users/AddEditUser/AddEditUser.jsx @@ -21,7 +21,8 @@ import colors from '@/themes/base/colors' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faFloppyDisk, faArrowLeft } from '@fortawesome/free-solid-svg-icons' import BCButton from '@/components/BCButton' -import { Box, Stack, Typography } from '@mui/material' +import { Box, Stack } from '@mui/material' +import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2' import BCAlert from '@/components/BCAlert' import Loading from '@/components/Loading' @@ -232,10 +233,10 @@ export const AddEditUser = ({ userType }) => { {t('common:submitError')} )} - + {userID ? 'Edit' : 'Add'} user  {userType === 'bceid' && `to ${orgName}`} - +
@@ -310,9 +311,9 @@ export const AddEditUser = ({ userType }) => { ) } > - + {t('backBtn')} - + { /> } > - {t('saveBtn')} + {t('saveBtn')} diff --git a/frontend/src/views/Users/AddEditUser/components/BCeIDSpecificRoleFields.jsx b/frontend/src/views/Users/AddEditUser/components/BCeIDSpecificRoleFields.jsx index d0a30b0ff..95bb47b3a 100644 --- a/frontend/src/views/Users/AddEditUser/components/BCeIDSpecificRoleFields.jsx +++ b/frontend/src/views/Users/AddEditUser/components/BCeIDSpecificRoleFields.jsx @@ -1,4 +1,5 @@ -import { Box, Typography } from '@mui/material' +import { Box } from '@mui/material' +import BCTypography from '@/components/BCTypography' import { BCFormCheckbox, BCFormRadio } from '@/components/BCForm' import { nonGovRoles } from '@/constants/roles' import { bceidRoleOptions } from '../_schema' @@ -7,9 +8,9 @@ export const BCeIDSpecificRoleFields = ({ form, disabled, t }) => { const { control } = form return ( - + {t('admin:Roles')} - + { const { control } = form return ( - + {t('admin:Roles')} - + Date: Wed, 11 Dec 2024 13:27:16 -0800 Subject: [PATCH 13/15] refactor: replace typography with bctypography across components for consistency --- .../Organizations/ViewOrganization/ViewOrganization.jsx | 6 +++--- frontend/src/views/Transfers/components/TransferView.jsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx index 2bf32af03..5fbac39bc 100644 --- a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx +++ b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx @@ -5,7 +5,7 @@ import BCTypography from '@/components/BCTypography' import BCAlert from '@/components/BCAlert' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' import Loading from '@/components/Loading' -import { IconButton, Typography } from '@mui/material' +import { IconButton } from '@mui/material' // icons import colors from '@/themes/base/colors.js' import { faCirclePlus } from '@fortawesome/free-solid-svg-icons' @@ -175,10 +175,10 @@ export const ViewOrganization = () => { {t('org:complianceUnitBalance')}: - + {orgBalaceInfo?.totalBalance.toLocaleString()} ( {Math.abs(orgBalaceInfo?.reservedBalance).toLocaleString()}) - + { backgroundColor: 'transparent.main' }} > - + {fromOrganization} {t('transfer:transfers')} {quantity} @@ -64,7 +64,7 @@ export const TransferView = ({ transferId, editorMode, transferData }) => { ${decimalFormatter({ value: pricePerUnit })} {t('transfer:complianceUnitsPerTvo')} ${decimalFormatter(totalValue)} CAD. - + {/* Comments */} {transferData?.comments.length > 0 && ( From d668ffdf76eb1f2fcc70c0ed53542a770e61f4d3 Mon Sep 17 00:00:00 2001 From: Alex Zorkin Date: Wed, 11 Dec 2024 13:39:34 -0800 Subject: [PATCH 14/15] chore: testing parallel testing workflow file --- .github/workflows/docker-auto-test.yaml | 167 ++++++------------------ 1 file changed, 43 insertions(+), 124 deletions(-) diff --git a/.github/workflows/docker-auto-test.yaml b/.github/workflows/docker-auto-test.yaml index cafe32b48..a60142e70 100644 --- a/.github/workflows/docker-auto-test.yaml +++ b/.github/workflows/docker-auto-test.yaml @@ -6,9 +6,8 @@ on: - "*" jobs: - build-and-test: + backend-tests: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 with: @@ -37,14 +36,6 @@ jobs: restore-keys: | ${{ runner.os }}-poetry- - - name: Cache npm dependencies - uses: actions/cache@v3 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Cache Docker images uses: actions/cache@v3 with: @@ -53,30 +44,17 @@ jobs: restore-keys: | ${{ runner.os }}-docker- - # Commented out mochawesome installation as it's only needed for Cypress - # - name: Install mochawesome and marge - # run: | - # npm install mochawesome mochawesome-merge mochawesome-report-generator --save-dev - - name: Install Poetry run: pip install poetry==1.6.1 - name: Install backend dependencies run: | - # Ensure that pip, setuptools, and wheel are up to date pip install --upgrade pip setuptools wheel - - # Install Poetry dependencies cd backend poetry config virtualenvs.create false poetry install pip install pytest-github-actions-annotate-failures typing_extensions - - name: Install frontend dependencies - run: | - cd frontend - npm ci - - name: Fix docker-compose.yml run: | sed -i 's/: true/: "true"/g; s/: false/: "false"/g' docker-compose.yml @@ -110,94 +88,6 @@ jobs: name: pytest-results path: backend/pytest-results.xml - - name: Run frontend tests - id: frontend_tests - continue-on-error: true - run: | - cd frontend - npm run test:run -- --reporter=junit --outputFile=vitest-results.xml - env: - CI: true - - - name: Upload Vitest results - if: always() - uses: actions/upload-artifact@v4 - with: - name: vitest-results - path: frontend/vitest-results.xml - - # Commented out Cypress-related steps - # - name: Create cypress.env.json - # run: | - # echo '{ - # "admin_idir_username": "${{ secrets.ADMIN_IDIR_USERNAME }}", - # "admin_idir_password": "${{ secrets.ADMIN_IDIR_PASSWORD }}", - # "org1_bceid_username": "${{ secrets.ORG1_BCEID_USERNAME }}", - # "org1_bceid_password": "${{ secrets.ORG1_BCEID_PASSWORD }}", - # "org1_bceid_id": "${{ secrets.ORG1_BCEID_ID }}", - # "org1_bceid_userId": "${{ secrets.ORG1_BCEID_USERID }}", - # "org2_bceid_username": "${{ secrets.ORG2_BCEID_USERNAME }}", - # "org2_bceid_password": "${{ secrets.ORG2_BCEID_PASSWORD }}", - # "org2_bceid_id": "${{ secrets.ORG2_BCEID_ID }}", - # "org2_bceid_userId": "${{ secrets.ORG2_BCEID_USERID }}" - # }' > frontend/cypress.env.json - - # - name: Run Cypress tests - # id: cypress_tests - # continue-on-error: true - # uses: cypress-io/github-action@v6 - # with: - # command: npm run cypress:run - # wait-on: 'http://localhost:3000' - # working-directory: frontend - # env: - # ADMIN_IDIR_USERNAME: ${{ secrets.ADMIN_IDIR_USERNAME }} - # ADMIN_IDIR_PASSWORD: ${{ secrets.ADMIN_IDIR_PASSWORD }} - # org1_bceid_username: ${{ secrets.ORG1_BCEID_USERNAME }} - # org1_bceid_password: ${{ secrets.ORG1_BCEID_PASSWORD }} - # org1_bceid_id: ${{ secrets.ORG1_BCEID_ID }} - # org1_bceid_userId: ${{ secrets.ORG1_BCEID_USERID }} - # org2_bceid_username: ${{ secrets.ORG2_BCEID_USERNAME }} - # org2_bceid_password: ${{ secrets.ORG2_BCEID_PASSWORD }} - # org2_bceid_id: ${{ secrets.ORG2_BCEID_ID }} - # org2_bceid_userId: ${{ secrets.ORG2_BCEID_USERID }} - - # - name: Combine mochawesome reports - # run: | - # npx mochawesome-merge frontend/cypress/reports/*.json > frontend/cypress/reports/combined-report.json - - # - name: Generate HTML report - # run: | - # npx marge frontend/cypress/reports/combined-report.json --reportDir frontend/cypress/reports --inline - - # - name: Generate test summary - # run: | - # node generate-summary.js - - # - name: Post test summary as a comment - # if: always() - # run: | - # SUMMARY=$(cat frontend/cypress/reports/test-summary.txt) - # gh pr comment ${{ github.event.pull_request.number }} --body "$SUMMARY" - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # - name: Upload Cypress results - # if: always() - # uses: actions/upload-artifact@v4 - # with: - # name: cypress-results - # path: | - # frontend/cypress/reports/ - # frontend/cypress/screenshots/ - - # - name: Post Cypress results as a comment - # if: always() - # run: | - # gh pr comment ${{ github.event.pull_request.number }} --body "Cypress test report is available [here](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}). Download the 'cypress-results' artifact to view the report." - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Stop services if: always() run: docker-compose down @@ -214,6 +104,48 @@ jobs: report_individual_runs: "true" deduplicate_classes_by_file_name: "true" + + frontend-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "20" + + - name: Cache npm dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Install frontend dependencies + run: | + cd frontend + npm ci + + - name: Run frontend tests + id: frontend_tests + continue-on-error: true + run: | + cd frontend + npm run test:run -- --reporter=junit --outputFile=vitest-results.xml + env: + CI: true + + - name: Upload Vitest results + if: always() + uses: actions/upload-artifact@v4 + with: + name: vitest-results + path: frontend/vitest-results.xml + - name: Publish Frontend Test Results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() @@ -225,16 +157,3 @@ jobs: fail_on: "errors" report_individual_runs: "true" deduplicate_classes_by_file_name: "true" - - - name: Check test results - if: always() - run: | - if [ "${{ steps.backend_tests.outcome }}" == "failure" ] || \ - [ "${{ steps.frontend_tests.outcome }}" == "failure" ]; then - # Note: When re-enabling Cypress tests, add this condition: - # || [ "${{ steps.cypress_tests.outcome }}" == "failure" ] - echo "One or more tests failed" - exit 1 - else - echo "All tests passed" - fi From f30fc9bbe170ad8333928a18cae973ba8a802ab0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:07:54 +0000 Subject: [PATCH 15/15] chore(deps): bump nanoid from 3.3.7 to 3.3.8 in /frontend Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.7 to 3.3.8. - [Release notes](https://github.com/ai/nanoid/releases) - [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md) - [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8) --- updated-dependencies: - dependency-name: nanoid dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f1e8793f7..129680549 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16272,15 +16272,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" },