Skip to main content

Utility Specific Calculation


Overview

This document explains the architecture of the utility billing calculation system, focusing on how the BaseCalculatorComponent class serves as a foundation that is extended by utility-specific implementations in the UtilitySpecificCalculation class.

BaseCalculatorComponent

The BaseCalculatorComponent provides a reusable foundation for utility billing calculations with standardized methods for:

  1. Base charge calculations - Computing the fundamental usage charges
  2. Variable rate handling - Supporting tiered pricing, time-of-use rates, and fixed rates
  3. Extra charge calculations - Managing additional fees, taxes, and service charges

This design follows the Template Method pattern, where the base class defines the skeleton of operations while allowing subclasses to override specific steps without changing the overall algorithm structure.

Component Hierarchy

BaseCalculatorComponent
    ↑
    |
UtilitySpecificCalculation
    |
    ├── RoshanCalculatorComponent
    ├── SamoaCalculatorComponent
    └── AxisCalculatorComponent

Extension Mechanism

UtilitySpecificCalculation

This class acts as a factory that creates and manages calculator components for different utilities:

def __init__(self, plan_data):
    self.plan_data = plan_data
    self.calculation_functions_for_utilities = {
        "Roshan Energy": self.RoshanCalculatorComponent(self.plan_data),
        "Samoa Water Utility": self.SamoaCalculatorComponent(self.plan_data),
        "Axis Meter Solution": self.AxisCalculatorComponent(self.plan_data),
        "Default Calculator Utility": {
            "samoa": self.SamoaCalculatorComponent(self.plan_data),
            "roshan": self.RoshanCalculatorComponent(self.plan_data),
            "axis": self.AxisCalculatorComponent(self.plan_data)
        }
    }

Each utility implementation extends BaseCalculatorComponent while adding utility-specific logic.

Detailed Extension Analysis

Common Inheritance Pattern

Each utility-specific component follows the same pattern:

  1. Initialize with a reference to the outer instance (for access to plan data)
  2. Override the base_calculator method to customize the calculation flow
  3. Add utility-specific methods for specialized charge calculations

Roshan Energy Implementation

The Roshan implementation adds specialized handling for:

  • Water service charges with waste water calculations
  • Electric service with delivery rates and state regulatory fees
  • Discount calculations specific to their billing model

Samoa Water Utility Implementation

This implementation relies entirely on the base component's calculations without adding extra logic.

Axis Meter Solution Implementation

The Axis implementation specializes in:

  • Electric-specific charges including regulatory and delivery charges
  • Ontario Electricity Rebate calculations
  • Late payment charge calculations based on balance and payment

Key Extension Points

1. Rate Type Handling

The base component supports three main rate types:

  • FIXED - A constant charge regardless of consumption
  • VARIABLE - Further divided into:
    • Time of Use - Different rates based on time periods
    • Tiered - Different rates based on consumption thresholds

Utility-specific implementations can customize how these are applied.

2. Extra Charge Calculation

The _calculate_extra_charges method is a primary extension point where each utility adds:

  • Service-specific fees
  • Regulatory charges
  • Delivery fees
  • Discounts and rebates

3. Late Charge Calculation

The calculate_late_charges method provides utility-specific late payment handling.

Calculation Flow

  1. Base charge calculation for all meters
  2. Utility-specific extra charge calculation
    • Service-specific charges (Water, Electricity)
    • Meter-specific charges
  3. Common extra charges applicable to all services
  4. Late charge calculation (if applicable)

Benefits of This Architecture

  1. Code Reuse - Common calculation logic is defined once in the base component
  2. Extensibility - New utilities can be added by creating a new component class
  3. Consistency - All utilities follow the same calculation structure
  4. Maintainability - Changes to the base calculation logic are automatically inherited by all utilities

Adding a New Utility Calculator Component

To extend the system with a new utility billing calculator, follow these steps:

  1. Create a new component class
    • Define a new nested class within the UtilitySpecificCalculation class
    • Inherit from BaseCalculatorComponent
    • Implement the __init__ method with a reference to the outer instance
  2. Implement required methods
    • Override the base_calculator method to implement the main calculation flow
    • Call the parent base_calculator method to leverage the existing logic
    • Add utility-specific extra charge calculations
  3. Add specialized methods
    • Implement service-specific methods (e.g., for water or electricity)
    • Override the _calculate_extra_charges method for custom fees
    • If needed, implement calculate_late_charges for custom late payment handling
  4. Register the new calculator
    • Add the new calculator to the calculation_functions_for_utilities dictionary in the UtilitySpecificCalculation constructor
    • Use the utility name as the key and an instance of your new calculator as the value
    • Add a reference in the "Default Calculator Utility" dictionary if applicable
  5. Implement utility-specific business logic
    • Add methods for service-specific calculations
    • Ensure all required charges are computed and added to the bill JSON
    • Follow the established patterns for consistency
  6. Test thoroughly
    • Verify that calculations work with different rate types
    • Ensure all required charges are included
    • Check that rounding is handled correctly

Conclusion

The BaseCalculatorComponent provides a flexible foundation for utility billing calculations that can be extended to accommodate the specific billing requirements of different utility providers. The inheritance-based design enables code reuse while allowing for customization where needed, creating a maintainable and extensible billing system.