From f7653dae83fd3b8b2cba66fdb1016c1525aa328d Mon Sep 17 00:00:00 2001 From: Dylan Leard Date: Tue, 7 Jan 2025 14:55:55 -0800 Subject: [PATCH] test: add test for compliance_service internal functions --- .../tests/service/test_compliance_service.py | 267 ++++++++++++++++++ .../reporting/tests/utils/baker_recipes.py | 10 +- 2 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 bc_obps/reporting/tests/service/test_compliance_service.py diff --git a/bc_obps/reporting/tests/service/test_compliance_service.py b/bc_obps/reporting/tests/service/test_compliance_service.py new file mode 100644 index 0000000000..c5b1de9715 --- /dev/null +++ b/bc_obps/reporting/tests/service/test_compliance_service.py @@ -0,0 +1,267 @@ +from django.test import TestCase +from decimal import Decimal +from reporting.models.report_product import ReportProduct +from reporting.models.emission_category import EmissionCategory +from reporting.models.report import Report +from registration.models.operation import Operation +from reporting.service.compliance_service import ComplianceService +from model_bakery.baker import make_recipe + + +class TestComplianceSummaryService(TestCase): + def test_get_regulatory_values_by_naics_code(self): + ## SETUP ## + # Create report version records with recipes + report_version_1 = make_recipe("reporting.tests.utils.report_version") + report_version_2 = make_recipe("reporting.tests.utils.report_version") + # Override parent values auto-generated by recipe + operation = Operation.objects.get(pk=report_version_1.report.operation.id) + report = Report.objects.get(pk=report_version_1.report_id) + operation.naics_code_id = 1 + operation.save() + report.reporting_year_id = 2024 + report.save() + operation = Operation.objects.get(pk=report_version_2.report.operation.id) + report = Report.objects.get(pk=report_version_2.report_id) + operation.naics_code_id = 22 + operation.save() + report.reporting_year_id = 2024 + report.save() + + ## TESTS ## + # Test service function returns correct values + regulatory_values_1 = ComplianceService.get_regulatory_values_by_naics_code(report_version_1.id) + regulatory_values_2 = ComplianceService.get_regulatory_values_by_naics_code(report_version_2.id) + + assert regulatory_values_1.reduction_factor == Decimal('0.6500') + assert regulatory_values_1.tightening_rate == Decimal('0.0100') + assert regulatory_values_2.reduction_factor == Decimal('0.9000') + assert regulatory_values_2.tightening_rate == Decimal('0.0100') + + def test_get_emissions_attributable_for_reporting(self): + ## SETUP ## + # Create report_emission records with recipes + report_emission_1 = make_recipe( + "reporting.tests.utils.report_emission", + json_data={"equivalentEmission": 100.0001}, + ) + report_emission_2 = make_recipe( + "reporting.tests.utils.report_emission", + report_version=report_emission_1.report_version, + json_data={"equivalentEmission": 200.9988}, + ) + report_emission_3 = make_recipe( + "reporting.tests.utils.report_emission", + report_version=report_emission_1.report_version, + json_data={"equivalentEmission": 300.05}, + ) + + # Set emission categories for report_emission records + # emission_category id 1 = Flaring, 3 = Industrial Process, 4 = On-site transportation, 12 = excluded non-biomass + report_emission_1.emission_categories.set([1]) + report_emission_2.emission_categories.set([3]) + report_emission_3.emission_categories.set([4, 12]) + + ## TESTS ## + # Only basic should be counted, report_emission_3 should not be counted twice + sum_for_testing = ComplianceService.get_emissions_attributable_for_reporting( + report_emission_1.report_version_id + ) + emission_sum = ( + Decimal(str(report_emission_1.json_data['equivalentEmission'])) + + Decimal(str(report_emission_2.json_data['equivalentEmission'])) + + Decimal(str(report_emission_3.json_data['equivalentEmission'])) + ) + assert sum_for_testing == emission_sum + + def test_get_production_totals(self): + ## SETUP ## + report_product_1 = make_recipe( + "reporting.tests.utils.report_product", + annual_production=Decimal('10000'), + production_data_apr_dec=Decimal('5000'), + ) + report_product_2 = make_recipe( + "reporting.tests.utils.report_product", + report_version=report_product_1.report_version, + annual_production=Decimal('100000'), + production_data_apr_dec=Decimal('25000'), + ) + report_product_3 = make_recipe( + "reporting.tests.utils.report_product", + report_version=report_product_1.report_version, + annual_production=Decimal('200000'), + production_data_apr_dec=Decimal('150000'), + ) + + ## TESTS ## + sums_for_testing = ComplianceService.get_production_totals(report_product_1.report_version_id) + annual_sum = ( + report_product_1.annual_production + report_product_2.annual_production + report_product_3.annual_production + ) + apr_dec_sum = ( + report_product_1.production_data_apr_dec + + report_product_2.production_data_apr_dec + + report_product_3.production_data_apr_dec + ) + + assert sums_for_testing['annual_amount'] == annual_sum + assert sums_for_testing['apr_dec'] == apr_dec_sum + + def test_get_allocated_emissions_by_report_product_emission_category(self): + ## SETUP ## + allocation_1 = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + emission_category=EmissionCategory.objects.get(pk=1), + allocated_quantity=Decimal('1000.0001'), + ) + allocation_2 = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + report_version=allocation_1.report_version, + emission_category=EmissionCategory.objects.get(pk=1), + report_product=allocation_1.report_product, + allocated_quantity=Decimal('2000.0002'), + ) + allocation_3 = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + report_version=allocation_1.report_version, + emission_category=EmissionCategory.objects.get(pk=3), + allocated_quantity=Decimal('6000.0006'), + ) + allocation_4 = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + report_version=allocation_1.report_version, + emission_category=EmissionCategory.objects.get(pk=12), + report_product=allocation_3.report_product, + allocated_quantity=Decimal('500.0005'), + ) + + ## TESTS ## + allocated_to_flaring_for_test = ComplianceService.get_allocated_emissions_by_report_product_emission_category( + allocation_1.report_version_id, allocation_1.report_product.product_id, [1] + ) + allocated_to_industrial_for_test = ( + ComplianceService.get_allocated_emissions_by_report_product_emission_category( + allocation_3.report_version_id, allocation_3.report_product.product_id, [3] + ) + ) + allocated_to_excluded_non_biomass_for_test = ( + ComplianceService.get_allocated_emissions_by_report_product_emission_category( + allocation_4.report_version_id, allocation_4.report_product.product_id, [12] + ) + ) + assert allocated_to_flaring_for_test == allocation_1.allocated_quantity + allocation_2.allocated_quantity + assert allocated_to_industrial_for_test == allocation_3.allocated_quantity + assert allocated_to_excluded_non_biomass_for_test == allocation_4.allocated_quantity + + def test_get_report_product_aggregated_totals(self): + ## SETUP ## + report_product_1 = make_recipe( + "reporting.tests.utils.report_product", + annual_production=Decimal('10000.0001'), + production_data_apr_dec=Decimal('5000.05'), + ) + report_product_2 = make_recipe( + "reporting.tests.utils.report_product", + report_version=report_product_1.report_version, + product=report_product_1.product, + annual_production=Decimal('100000.003'), + production_data_apr_dec=Decimal('25000.0002'), + ) + report_product_3 = make_recipe( + "reporting.tests.utils.report_product", + report_version=report_product_1.report_version, + annual_production=Decimal('200000.0091'), + production_data_apr_dec=Decimal('150000.1234'), + ) + report_product_4 = make_recipe( + "reporting.tests.utils.report_product", + report_version=report_product_1.report_version, + product=report_product_3.product, + annual_production=Decimal('400000.002'), + production_data_apr_dec=Decimal('50000.321'), + ) + + ## TESTS ## + product_1_2_aggregate_for_test = ComplianceService.get_report_product_aggregated_totals( + report_product_1.report_version_id, report_product_1.product_id + ) + product_3_4_aggregate_for_test = ComplianceService.get_report_product_aggregated_totals( + report_product_3.report_version_id, report_product_3.product_id + ) + + assert ( + product_1_2_aggregate_for_test['annual_amount'] + == report_product_1.annual_production + report_product_2.annual_production + ) + assert ( + product_1_2_aggregate_for_test['apr_dec'] + == report_product_1.production_data_apr_dec + report_product_2.production_data_apr_dec + ) + + assert ( + product_3_4_aggregate_for_test['annual_amount'] + == report_product_3.annual_production + report_product_4.annual_production + ) + assert ( + product_3_4_aggregate_for_test['apr_dec'] + == report_product_3.production_data_apr_dec + report_product_4.production_data_apr_dec + ) + + def test_get_reporting_only_allocated(self): + ## SETUP ## + allocation_1 = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + emission_category=EmissionCategory.objects.get(pk=1), + allocated_quantity=Decimal('1000.0001'), + ) + allocation_2 = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + report_version=allocation_1.report_version, + emission_category=EmissionCategory.objects.get(pk=2), + report_product=allocation_1.report_product, + allocated_quantity=Decimal('2000.0002'), + ) + make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + report_version=allocation_1.report_version, + emission_category=EmissionCategory.objects.get(pk=3), + report_product=allocation_1.report_product, + allocated_quantity=Decimal('6000.0006'), + ) + allocation_4 = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + report_version=allocation_1.report_version, + emission_category=EmissionCategory.objects.get(pk=12), + report_product=allocation_1.report_product, + allocated_quantity=Decimal('500.0005'), + ) + + ## TESTS ## + # Correctly aggregates reporting-only emissions + reporting_only_for_test = ComplianceService.get_reporting_only_allocated( + allocation_1.report_version, allocation_1.report_product.product_id + ) + assert reporting_only_for_test == allocation_2.allocated_quantity + allocation_4.allocated_quantity + + # Add a fog product + fog_product_allocation = make_recipe( + "reporting.tests.utils.report_product_emission_allocation", + report_version=allocation_1.report_version, + emission_category=EmissionCategory.objects.get(pk=1), + allocated_quantity=Decimal('12.0'), + ) + rp = ReportProduct.objects.get(pk=fog_product_allocation.report_product_id) + rp.product_id = 39 + rp.save() + + # Correctly aggregates reporting-only emissions when there is a fog product + reporting_only_with_fog_for_test = ComplianceService.get_reporting_only_allocated( + allocation_1.report_version, allocation_1.report_product.product_id + ) + assert ( + reporting_only_with_fog_for_test + == allocation_2.allocated_quantity + + allocation_4.allocated_quantity + + fog_product_allocation.allocated_quantity + ) diff --git a/bc_obps/reporting/tests/utils/baker_recipes.py b/bc_obps/reporting/tests/utils/baker_recipes.py index bba5919408..7534ffd011 100644 --- a/bc_obps/reporting/tests/utils/baker_recipes.py +++ b/bc_obps/reporting/tests/utils/baker_recipes.py @@ -1,6 +1,6 @@ from datetime import date, timedelta, datetime from typing import Any - +from reporting.models.report_product_emission_allocation import ReportProductEmissionAllocation from registration.models import NaicsCode from registration.models.activity import Activity from reporting.models import ReportNewEntrant, ReportNewEntrantEmission, ReportNewEntrantProduction @@ -199,3 +199,11 @@ def json_seq(json_key="generated_json", json_value="test json value", seq_value: NaicsCode, naics_code='12345', ) + +report_product_emission_allocation = Recipe( + ReportProductEmissionAllocation, + report_version=foreign_key(report_version), + facility_report=foreign_key(facility_report), + report_product=foreign_key(report_product), + emission_category=foreign_key(emission_category), +)