Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore/compliance summary tests #2597

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions bc_obps/reporting/api/compliance_data.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from typing import Literal, Tuple
from common.permissions import authorize
from django.http import HttpRequest
from registration.decorators import handle_http_errors
from reporting.constants import EMISSIONS_REPORT_TAGS
from service.error_service.custom_codes_4xx import custom_codes_4xx
from reporting.schema.generic import Message
from reporting.service.compliance_service import ComplianceService
from reporting.service.compliance_service import ComplianceService, ComplianceData
from reporting.schema.compliance_data import ComplianceDataSchemaOut
from .router import router
from common.permissions import authorize


@router.get(
Expand All @@ -19,9 +19,7 @@
auth=authorize("approved_industry_user"),
)
@handle_http_errors()
def get_compliance_summary_data(
request: HttpRequest, report_version_id: int
) -> Tuple[Literal[200], ComplianceDataSchemaOut]:
def get_compliance_summary_data(request: HttpRequest, report_version_id: int) -> Tuple[Literal[200], ComplianceData]:
compliance_data = ComplianceService.get_calculated_compliance_data(report_version_id)

return 200, compliance_data
70 changes: 61 additions & 9 deletions bc_obps/reporting/service/compliance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,74 @@
from reporting.models.report_product_emission_allocation import ReportProductEmissionAllocation
from reporting.models.report_product import ReportProduct
from reporting.models import NaicsRegulatoryValue, ReportVersion
from reporting.schema.compliance_data import RegulatoryValueSchema
from reporting.schema.compliance_data import ReportProductComplianceSchema, ComplianceDataSchemaOut
from reporting.models.product_emission_intensity import ProductEmissionIntensity
from reporting.models.emission_category import EmissionCategory
from decimal import Decimal
from django.db.models import Sum
from typing import Dict, List


class RegulatoryValues:
def __init__(
self,
reduction_factor: Decimal,
tightening_rate: Decimal,
initial_compliance_period: int,
compliance_period: int,
):
self.reduction_factor = reduction_factor
self.tightening_rate = tightening_rate
self.initial_compliance_period = initial_compliance_period
self.compliance_period = compliance_period


class ReportProductComplianceData:
def __init__(
self,
name: str,
annual_production: Decimal | int,
apr_dec_production: Decimal | int,
emission_intensity: Decimal,
allocated_industrial_process_emissions: Decimal | int,
allocated_compliance_emissions: Decimal | int,
):
self.name = name
self.annual_production = annual_production
self.apr_dec_production = apr_dec_production
self.emission_intensity = emission_intensity
self.allocated_industrial_process_emissions = allocated_industrial_process_emissions
self.allocated_compliance_emissions = allocated_compliance_emissions


class ComplianceData:
def __init__(
self,
emissions_attributable_for_reporting: Decimal | int,
reporting_only_emissions: Decimal | int,
emissions_attributable_for_compliance: Decimal | int,
emissions_limit: Decimal | int,
excess_emissions: Decimal | int,
credited_emissions: Decimal | int,
regulatory_values: RegulatoryValues,
products: List[ReportProductComplianceData],
):
self.emissions_attributable_for_reporting = emissions_attributable_for_reporting
self.reporting_only_emissions = reporting_only_emissions
self.emissions_attributable_for_compliance = emissions_attributable_for_compliance
self.emissions_limit = emissions_limit
self.excess_emissions = excess_emissions
self.credited_emissions = credited_emissions
self.regulatory_values = regulatory_values
self.products = products


class ComplianceService:
"""
Service that fetches the data & performs the calculations necessary for the compliance summary
"""

@staticmethod
def get_regulatory_values_by_naics_code(report_version_id: int) -> RegulatoryValueSchema:
def get_regulatory_values_by_naics_code(report_version_id: int) -> RegulatoryValues:
data = ReportVersion.objects.select_related('report__operation').get(pk=report_version_id)
naics_code_id = data.report.operation.naics_code_id
compliance_year = data.report.reporting_year.reporting_year
Expand All @@ -27,7 +79,7 @@ def get_regulatory_values_by_naics_code(report_version_id: int) -> RegulatoryVal
valid_to__gte=data.report.reporting_year.reporting_window_end,
)

return RegulatoryValueSchema(
return RegulatoryValues(
reduction_factor=regulatory_values.reduction_factor,
tightening_rate=regulatory_values.tightening_rate,
initial_compliance_period=2024,
Expand Down Expand Up @@ -112,19 +164,19 @@ def calculate_product_emission_limit(
product_emission_limit = (apr_dec_production * pwaei) * (
reduction_factor
- (
(Decimal(1) - (allocated_industrial_process / allocated_for_compliance))
(Decimal('1') - (allocated_industrial_process / allocated_for_compliance))
* tightening_rate
* (compliance_period - initial_compliance_period)
)
)
return product_emission_limit

@classmethod
def get_calculated_compliance_data(cls, report_version_id: int) -> ComplianceDataSchemaOut:
def get_calculated_compliance_data(cls, report_version_id: int) -> ComplianceData:
naics_data = ComplianceService.get_regulatory_values_by_naics_code(report_version_id)
registration_purpose = ReportVersion.objects.get(pk=report_version_id).report.operation.registration_purpose
##### Don't use schemas, use classes or dicts
compliance_product_list: List[ReportProductComplianceSchema] = []
compliance_product_list: List[ReportProductComplianceData] = []
total_allocated_reporting_only = Decimal(0)
total_allocated_for_compliance = Decimal(0)
total_allocated_for_compliance_2024 = Decimal(0)
Expand Down Expand Up @@ -173,7 +225,7 @@ def get_calculated_compliance_data(cls, report_version_id: int) -> ComplianceDat

# Add product to list of products
compliance_product_list.append(
ReportProductComplianceSchema(
ReportProductComplianceData(
name=rp.product.name,
annual_production=production_totals["annual_amount"],
apr_dec_production=production_totals["apr_dec"],
Expand All @@ -198,7 +250,7 @@ def get_calculated_compliance_data(cls, report_version_id: int) -> ComplianceDat
excess_emissions = Decimal(0)
credited_emissions = Decimal(0)
# Craft return object with all data
return_object = ComplianceDataSchemaOut(
return_object = ComplianceData(
emissions_attributable_for_reporting=attributable_for_reporting_total,
reporting_only_emissions=round(Decimal(total_allocated_reporting_only), 4),
emissions_attributable_for_compliance=round(total_allocated_for_compliance_2024, 4),
Expand Down
Loading
Loading