60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
from app.models.attribution_record import AttributionRecord
|
|
|
|
|
|
class ROICalculator:
|
|
INDUSTRY_AVG_CITATION_VALUE = 50.0
|
|
|
|
def calculate_roi(
|
|
self,
|
|
subscription_cost: float,
|
|
score_delta: float,
|
|
attribution_records: list[AttributionRecord],
|
|
) -> dict:
|
|
value_generated = score_delta * self.INDUSTRY_AVG_CITATION_VALUE
|
|
if subscription_cost > 0:
|
|
roi_percentage = round(
|
|
(value_generated - subscription_cost) / subscription_cost * 100, 2
|
|
)
|
|
else:
|
|
roi_percentage = 0.0
|
|
break_even_delta = self.estimate_break_even(subscription_cost)
|
|
return {
|
|
"roi_percentage": roi_percentage,
|
|
"value_generated": round(value_generated, 2),
|
|
"cost": subscription_cost,
|
|
"break_even_delta": round(break_even_delta, 2),
|
|
}
|
|
|
|
def generate_ab_comparison(
|
|
self,
|
|
before_score: float,
|
|
after_score: float,
|
|
before_dimensions: dict,
|
|
after_dimensions: dict,
|
|
) -> dict:
|
|
overall_delta = round(after_score - before_score, 2)
|
|
dimensions = []
|
|
all_names = set(list(before_dimensions.keys()) + list(after_dimensions.keys()))
|
|
for name in all_names:
|
|
b = before_dimensions.get(name, {}).get("score", 0)
|
|
a = after_dimensions.get(name, {}).get("score", 0)
|
|
delta = round(a - b, 2)
|
|
dimensions.append({
|
|
"name": name,
|
|
"before": b,
|
|
"after": a,
|
|
"delta": delta,
|
|
"improved": delta > 0,
|
|
})
|
|
return {
|
|
"overall_before": before_score,
|
|
"overall_after": after_score,
|
|
"overall_delta": overall_delta,
|
|
"dimensions": dimensions,
|
|
}
|
|
|
|
def estimate_break_even(self, subscription_cost: float) -> float:
|
|
if self.INDUSTRY_AVG_CITATION_VALUE == 0:
|
|
return 0.0
|
|
return subscription_cost / self.INDUSTRY_AVG_CITATION_VALUE
|