Skip to content

Commit

Permalink
Merge branch 'master' into enhancement/activity-based-cost-model
Browse files Browse the repository at this point in the history
  • Loading branch information
metroid-samus committed Jan 19, 2024
2 parents fd85473 + 794a478 commit c7de4d2
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 11 deletions.
105 changes: 105 additions & 0 deletions docs/docs/user-guide/cost_model.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Cost Model

Our Cost Model is a feature that enables teams to estimate response cost for each incident. Users can opt in to create and use personalized cost calculations for each incident based on participant activity.

If no cost model is assigned to an incident, the default classic cost model will be used. See [Incident Cost Type](../administration/settings/incident/incident-cost-type.mdx###calculating-incident-cost).

<div style={{textAlign: 'center'}}>

![](/img/admin-ui-cost-model.png)

</div>

## Key Features

### Customizable Cost Models
Users have the flexibility to define their unique cost models based on their organization's workflow and tools. This customization can be tailored to each incident, providing a versitile approach to cost calculation. The cost model for an incident can be changed at any time during its lifespan. All participant activity costs moving forward will be calculated using the new cost model.

### Plugin-Based Tracking
Users can track costs from their existing tools by using our plugin-based tracking system. Users have the flexibility to select which plugins and specific plugin events they want to track, offering a targeted approach to cost calculation.

### Effort Assignment
For each tracked activity, users can assign a quantifiable measure of effort, represented in seconds of work time. This feature provides a more accurate representation of the cost of an incident.

### Incident Cost Calculation
Incident cost calculation is based on the cost model and effort assignment for each tracked participant activity. This helps in understanding resource utilization and cost of an incident.


## Currently Supported Plugin Events

### Slack: Channel Activity
This event tracks activity within a specific Slack channel. By periodically polling channel messages, this gathers insights into the activity and engagement levels of each participant.

### Slack: Thread Activity
This event tracks activity within a specific Slack thread. By periodically polling thread replies, this gathers insights into the activity and engagement levels of each participant.


<div style={{textAlign: 'center'}}>

![](/img/admin-ui-edit-cost-model.png)

</div>

## Cost Calculation Examples

Below, we illustrate the use of the cost model through two examples. These are based on the following values:

<b>Cost Model 1</b>

| Plugin Event | Response Time (seconds)
| ------------ | -------------
| Slack Channel Activity | 300

The employee hourly rate can be adjusted by modifying the `Annual Employee Cost` and `Business Year Hours` fields in the [project settings](../administration/settings/project.mdx). In these examples, we will use the following value:
```
hourly_rate = 100
```

#### Example 1

Consider the following Slack channel activity for `Incident 1`:

| Slack Channel Activity Timestamp | Participant
| ------------ | -------------
| 100 | Cookie Doe
| 200 | Nate Flex

The resulting recorded participant activity will be:

| Participant | started_at | ended_at | Plugin Event | Incident
| ------------ | ------------- | ------------- | ------------- | -------------
| Cookie Doe | 100 | 400 | Slack Channel Activity | Incident 1
| Nate Flex | 200 | 500 | Slack Channel Activity | Incident 1


The incident cost is then calculated as:

```
( (400 - 100) + (500-200) ) / SECONDS_IN_HOUR * hourly_rate = $16.67
```

#### Example 2

Consider the following Slack channel activity for `Incident 2`:

| Slack Channel Activity Timestamp | Participant
| ------------ | -------------
| 100 | Cookie Doe
| 150 | Cookie Doe
| 200 | Nate Flex
| 500 | Cookie Doe

The resulting recorded participant activity will be:

| Participant | started_at | ended_at | Plugin Event | Incident
| ------------ | ------------- | ------------- | ------------- | -------------
| Cookie Doe | 100 | 450 | Slack Channel Activity | Incident 2
| Nate Flex | 200 | 500 | Slack Channel Activity | Incident 2
| Cookie Doe | 500 | 800 | Slack Channel Activity | Incident 2


The incident cost is then calculated as:

```
( (450 - 100) + (500 - 200) + (800 - 500) ) / SECONDS_IN_HOUR * hourly_rate = $26.39
```
18 changes: 8 additions & 10 deletions src/dispatch/incident/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,6 @@ def incident_create_resources(*, incident: Incident, db_session=None) -> Inciden
individual_participants, team_participants = get_incident_participants(incident, db_session)
tactical_participant_emails = [i.email for i, _ in individual_participants]

# we add any observer added in create (like new oncall participant)
participant_with_observer_role = participant_service.get_by_incident_id_and_role(
db_session=db_session, incident_id=incident.id, role=ParticipantRoleType.observer
)
if participant_with_observer_role:
# add to list
individual_participants.append(
(participant_with_observer_role.individual, participant_with_observer_role.service_id)
)

# we create the tactical group
if not incident.tactical_group:
group_flows.create_group(
Expand Down Expand Up @@ -251,6 +241,14 @@ def incident_create_resources(*, incident: Incident, db_session=None) -> Inciden
]
user_emails = list(dict.fromkeys(user_emails))

# we add any observer added in create (like new oncall participant)
participant_with_observer_role = participant_service.get_by_incident_id_and_role(
db_session=db_session, incident_id=incident.id, role=ParticipantRoleType.observer
)
if participant_with_observer_role:
# add to list
user_emails.append(participant_with_observer_role.individual.email)

for user_email in user_emails:
# we add the participant to the tactical group
group_flows.update_group(
Expand Down
2 changes: 1 addition & 1 deletion src/dispatch/participant/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def get_by_incident_id_and_service_id(
db_session.query(Participant)
.filter(Participant.incident_id == incident_id)
.filter(Participant.service_id == service_id)
.one_or_none()
.first()
)


Expand Down

0 comments on commit c7de4d2

Please sign in to comment.