Skip to content

Commit 38acbe9

Browse files
Do not round up incident cost (Netflix#5180)
* Do not round up incident cost * Fixes typing * Fixes typing. * Fixes test * Removes unused import. * Fixes tests * Fixes function annotations. * Fixes function annotations
1 parent b2cd9b5 commit 38acbe9

File tree

2 files changed

+17
-22
lines changed

2 files changed

+17
-22
lines changed

src/dispatch/incident_cost/service.py

+12-14
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,9 @@ def update_incident_response_cost_for_incident_type(
146146

147147
def calculate_response_cost(
148148
hourly_rate, total_response_time_seconds, incident_review_hours=0
149-
) -> int:
150-
"""Calculates and rounds up the incident response cost."""
151-
return math.ceil(
152-
((total_response_time_seconds / SECONDS_IN_HOUR) + incident_review_hours) * hourly_rate
153-
)
149+
) -> float:
150+
"""Calculates the incident response cost."""
151+
return ((total_response_time_seconds / SECONDS_IN_HOUR) + incident_review_hours) * hourly_rate
154152

155153

156154
def get_default_incident_response_cost(
@@ -235,7 +233,7 @@ def fetch_incident_events(
235233

236234
def calculate_incident_response_cost_with_cost_model(
237235
incident: Incident, db_session: SessionLocal
238-
) -> int:
236+
) -> float:
239237
"""Calculates the cost of an incident using the incident's cost model.
240238
241239
This function aggregates all new incident costs based on plugin activity since the last incident cost update.
@@ -246,7 +244,7 @@ def calculate_incident_response_cost_with_cost_model(
246244
db_session: The database session.
247245
248246
Returns:
249-
int: The incident response cost in dollars.
247+
float: The incident response cost in dollars.
250248
"""
251249

252250
participants_total_response_time_seconds = 0
@@ -304,12 +302,12 @@ def calculate_incident_response_cost_with_cost_model(
304302
total_response_time_seconds=participants_total_response_time_seconds,
305303
)
306304

307-
return incident.total_cost + amount
305+
return float(incident.total_cost) + amount
308306

309307

310308
def get_participant_role_time_seconds(
311309
incident: Incident, participant_role: ParticipantRole, start_at: datetime
312-
) -> int:
310+
) -> float:
313311
"""Calculates the time spent by a participant in an incident role starting from a given time.
314312
315313
The participant's time spent in the incident role is adjusted based on the role's engagement multiplier.
@@ -320,7 +318,7 @@ def get_participant_role_time_seconds(
320318
start_at: Only time spent after this will be considered.
321319
322320
Returns:
323-
int: The time spent by the participant in the incident role in seconds.
321+
float: The time spent by the participant in the incident role in seconds.
324322
"""
325323
if participant_role.renounced_at and participant_role.renounced_at < start_at:
326324
# skip calculating already-recorded activity
@@ -372,7 +370,7 @@ def get_participant_role_time_seconds(
372370
# TODO(mvilanova): adjust based on incident priority
373371
if participant_role_time_hours > HOURS_IN_DAY:
374372
days, hours = divmod(participant_role_time_hours, HOURS_IN_DAY)
375-
participant_role_time_hours = math.ceil(((days * HOURS_IN_DAY) / 3) + hours)
373+
participant_role_time_hours = ((days * HOURS_IN_DAY) / 3) + hours
376374

377375
# we make the assumption that participants spend more or less time based on their role
378376
# and we adjust the time spent based on that
@@ -410,7 +408,7 @@ def get_total_participant_roles_time_seconds(incident: Incident, start_at: datet
410408

411409
def calculate_incident_response_cost_with_classic_model(
412410
incident: Incident, db_session: SessionLocal, incident_review: bool = False
413-
) -> int:
411+
) -> float:
414412
"""Calculates the cost of an incident using the classic incident cost model.
415413
416414
This function aggregates all new incident costs since the last incident cost update. If this is the first time performing cost calculation for this incident, it computes the total costs from the incident's creation.
@@ -421,7 +419,7 @@ def calculate_incident_response_cost_with_classic_model(
421419
incident_review: Whether to add the incident review costs in this calculation.
422420
423421
Returns:
424-
int: The incident response cost in dollars.
422+
float: The incident response cost in dollars.
425423
"""
426424
last_update = incident.created_at
427425
incident_review_hours = 0
@@ -456,7 +454,7 @@ def calculate_incident_response_cost_with_classic_model(
456454
incident_review_hours=incident_review_hours,
457455
)
458456

459-
return incident_response_cost.amount + amount
457+
return float(incident_response_cost.amount) + amount
460458

461459

462460
def calculate_incident_response_cost(

tests/incident_cost/test_incident_cost_service.py

+5-8
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def test_calculate_incident_response_cost_with_cost_model(
109109
):
110110
"""Tests that the incident cost is calculated correctly when a cost model is enabled."""
111111
from datetime import timedelta
112-
import math
112+
from decimal import Decimal
113113
from dispatch.incident_cost.service import update_incident_response_cost, get_hourly_rate
114114
from dispatch.incident_cost_type import service as incident_cost_type_service
115115
from dispatch.participant_activity.service import (
@@ -150,15 +150,12 @@ def test_calculate_incident_response_cost_with_cost_model(
150150
participants_total_response_time_seconds += activity.ended_at - activity.started_at
151151
hourly_rate = get_hourly_rate(incident.project)
152152
expected_incident_cost = (
153-
math.ceil(
154-
(participants_total_response_time_seconds.seconds / SECONDS_IN_HOUR) * hourly_rate
155-
)
156-
+ orig_total_incident_cost
157-
)
153+
participants_total_response_time_seconds.seconds / SECONDS_IN_HOUR
154+
) * hourly_rate + orig_total_incident_cost
158155

159156
assert cost
160-
assert cost == expected_incident_cost
161-
assert cost == incident.total_cost
157+
assert cost == Decimal(expected_incident_cost).quantize(cost)
158+
assert cost == Decimal(incident.total_cost).quantize(cost)
162159

163160

164161
def test_calculate_incident_response_cost_with_cost_model__no_enabled_plugins(

0 commit comments

Comments
 (0)