Service Level Agreements
Introduction
This workflow enforces Service Level Agreements (SLA) for tickets from organizations.
Installation
This workflow is built into Cerb 11.0+. It will automatically update.
You can enable it from Search » Workflows » (+) » Service Level Agreements.
Usage
Adding SLA plans
An SLA plan contains an availability calendar and a response time target.
You can manage SLA plans from Search » Sla Plans.
A default Priority plan has been created for you, along with a business hour calendar and 2-hour response time target.
Assigning SLA plans to organizations
Navigate to Search » Organizations.
Edit an organization to assign an SLA plan to it.
Click the Add Fieldset button and select SLA.
Select an SLA plan. An optional expiration date is available if you sell annual subscriptions to priority support. Otherwise you can set this to a large number like +10 years
.
Click the Save Changes button to save the organization record.
Send a test message from that organization
You can simulate an inbound email in MIME format from Setup » Mail » Incoming » Import.
From: Maria Vasquez <maria.vasquez@baston.example>
To: support@cerb.example
Subject: Issues with email notifications not sending
Message-ID: <54321@baston.example>
Date: Fri, 18 Oct 2024 12:05:47 +0200
MIME-Version: 1.0
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 8bit
Hello Support Team,
We're currently having an issue with our email notifications not being sent out. Our team relies on these notifications for critical updates, and they've stopped being delivered in the past couple of days. I've checked the spam folders, and nothing is there either.
Is this a known issue? Could you please advise on how we can fix this as soon as possible?
Thank you for your help!
Best regards,
Maria Vasquez
IT Support
Baston Inc.
Add the SLA widget to ticket profiles
Navigate to the ticket profile page for your test message above from Search » Tickets.
Click on the Add Widget button at the top of the profile page.
Select SLA Deadline from the widget Library tab and click the Create button.
You can drag the new widget into your preferred placement from the drag handle in its top right corner when hovering over it.
The widget will change colors when a ticket is overdue.
Updating SLA hours
From Search » SLA Plans, edit a plan’s calendar to update the service operating hours.
You can add events and recurring events (like office holidays) to block out availability.
Sorting work by SLA
You can filter and sort ticket worklists by SLA:
sla.deadline:!null sort:sla.deadline
SLA deadline lifecycle
When a worker replies to a ticket with an SLA deadline and a non-open status, it will clear the deadline.
When a participant responds to the ticket without an existing SLA deadline, a new deadline will be added to the ticket.
Related workflows
You can enable the Sender Org By Hostname workflow to automatically add organizations to new contacts by email hostname. This will ensure they receive the appropriate SLA deadline.
Use the Auto Dispatcher workflow to give priority assignment to tickets with an approaching SLA deadline.
Reference
You can build your own Service Level Agreement workflow using this template as a reference.
Change occurrences of cerb.sla to your own workflow identifier. Use a prefix based on a domain you own (e.g. com.example.workflow
).
workflow:
name: cerb.sla
version: 2024-10-21T00:00:00Z
description: Enforce Service Level Agreements (SLA) for tickets from organizations
website: https://cerb.ai/workflows/cerb.sla/
requirements:
cerb_version: >=11.0 <11.1
cerb_plugins: cerberusweb.core
records:
custom_record/sla_plan:
fields:
name: SLA Plan
name_plural: SLA Plans
uri: sla_plan
params:
owners:
contexts@csv: cerberusweb.contexts.app
custom_field/sla_plan_calendar:
fields:
name: Calendar
context: sla_plan
uri: calendar
type: L
pos: 1
params:
context: calendar
custom_field/sla_plan_target_response_time:
fields:
name: Target Response Time
context: sla_plan
uri: target_response_time
type: S
pos: 2
custom_fieldset/fieldset_org_sla:
fields:
name: SLA
context: org
owner__context: app
owner_id@int: 0
custom_field/fieldset_org_sla_plan:
fields:
name: Plan
context: org
uri: sla_plan
type: L
pos: 1
custom_fieldset_id: {{records.fieldset_org_sla.id}}
params:
context: sla_plan
custom_field/fieldset_org_sla_expires:
fields:
name: Expires
context: org
uri: sla_expires
type: E
pos: 2
custom_fieldset_id: {{records.fieldset_org_sla.id}}
custom_fieldset/fieldset_ticket_sla:
fields:
name: SLA
context: ticket
owner__context: workflow
owner_id@int: {{workflow_id}}
custom_field/fieldset_ticket_sla_deadline:
fields:
name: Deadline
context: ticket
uri: sla_deadline
type: E
pos: 1
custom_fieldset_id: {{records.fieldset_ticket_sla.id}}
calendar/calendar_priority:
fields:
name: SLA Priority Schedule
owner__context: workflow
owner_id: {{workflow_id}}
timezone@text:
params:
manual_disabled: 0
sync_enabled: 0
start_on_mon: 1
hide_start_time: 0
color_available: #a0d95b
color_busy: #c8c8c8
calendar_recurring_event/recur_event_priority_available:
updatePolicy@csv:
fields:
name: Available
calendar_id: {{records.calendar_priority.id}}
is_available@int: 1
tz: America/Los_Angeles
event_start: 8am
event_end: 6pm
recur_start: 0
recur_end: 0
patterns: Weekdays
sla_plan/priority:
fields:
name: Priority
owner__context: app
owner_id@int: 0
calendar: {{records.calendar_priority.id}}
target_response_time: 2 hours
automation/automation_set_ticket_deadline:
fields:
name: cerb.sla.mailReceived.addDeadline
extension_id: cerb.trigger.mail.received
description: When the sender org of a new ticket has an SLA, add a deadline in business hours using a calendar
script@raw:
start:
# Calculate if the org has an SLA plan and the ticket has no deadline
outcome/validate:
if@bool:
{{
message_ticket_sla_deadline
or not message_ticket_org_sla_plan_id
or not message_ticket_org_sla_plan_calendar_id
or not message_ticket_org_sla_plan_target_response_time
}}
then:
return:
set:
sla_deadline@text:
{{
cerb_calendar_get_relative_date(
message_ticket_org_sla_plan_calendar_id,
message_ticket_org_sla_plan_target_response_time
)|date('r')
}}
outcome/hasDeadline:
if@bool: {{sla_deadline}}
then:
record.update/ticket:
output: updated_ticket
inputs:
record_type: ticket
record_id: {{message_ticket_id}}
fields:
sla_deadline@date: {{sla_deadline}}
policy_kata@raw:
commands:
record.update:
deny/type@bool: {{inputs.record_type is not record type ('ticket')}}
allow@bool: yes
automation_event_listener/listener_mail_received:
fields:
name: Service Level Agreements
event_name: mail.received
priority: 1
is_disabled: 0
event_kata@raw:
automation/assign:
uri: cerb:automation:cerb.sla.mailReceived.addDeadline
# Skip when sender has no org assigned
disabled@bool:
{{
message_ticket_sla_deadline
or not message_ticket_org_sla_plan_id
or not message_ticket_org_sla_plan_calendar_id
or not message_ticket_org_sla_plan_target_response_time
}}
automation/automation_reply_clear_sla_deadline:
fields:
name: cerb.sla.mailSent.clearDeadline
extension_id: cerb.trigger.mail.sent
description@text:
script@raw:
start:
# Only if we have an SLA deadline
outcome/validate:
if@bool:
{{
not message_ticket_sla_deadline
or not message_worker_id
}}
then:
return:
# Clear the SLA deadline on worker replies
record.update/ticket:
output: updated_ticket
inputs:
record_type: ticket
record_id: {{message_ticket_id}}
fields:
sla_deadline@int: 0
policy_kata@raw:
commands:
record.update:
deny/type@bool: {{inputs.record_type is not record type ('ticket')}}
allow@bool: yes
automation_event_listener/listener_mail_sent:
fields:
name: Service Level Agreements
event_name: mail.sent
priority: 1
is_disabled: 0
event_kata@raw:
automation/assign:
uri: cerb:automation:cerb.sla.mailSent.clearDeadline
# Only if we have an SLA deadline and it's not an auto-reply
disabled@bool:
{{
not message_ticket_sla_deadline
or not message_worker_id
}}
package/package_ticket_sla:
fields:
name: SLA Deadline
description: Display the SLA deadline for the current ticket
point: profile_widget:ticket
uri: cerb_profile_widget_sla_ticket_deadline
package_json@raw:
{
"package": {
"name": "SLA Ticket Deadline",
"revision": 1,
"requires": {
"cerb_version": "11.0.0",
"plugins": [
]
},
"library": {
"name": "SLA Ticket Deadline",
"uri": "cerb_profile_widget_sla_ticket_deadline",
"description": "Display the SLA deadline for the current ticket",
"point": "profile_widget:ticket"
},
"configure": {
"placeholders": [
],
"prompts": [
{
"type": "chooser",
"label": "Profile Dashboard",
"key": "profile_tab_id",
"hidden": true,
"params": {
"context": "cerberusweb.contexts.profile.tab",
"single": true,
"query": ""
}
}
]
}
},
"records": [
{
"uid": "profile_widget_sla_deadline",
"_context": "cerberusweb.contexts.profile.widget",
"name": "Service Level Agreement (SLA)",
"extension_id": "cerb.profile.tab.widget.sheet",
"profile_tab_id": "{{{profile_tab_id}}}",
"pos": 0,
"width_units": 4,
"zone": "sidebar",
"extension_params": {
"data_query": "type:worklist.records\r\nof:ticket\r\nexpand: [customfields,org_customfields]\r\nquery:(\r\n id:{{record_id}}\r\n limit:1\r\n sort:[id]\r\n)\r\nformat:dictionaries",
"cache_secs": "",
"placeholder_simulator_kata": "",
"sheet_kata": "layout:\r\n style: fieldsets\r\n headings@bool: no\r\n paging@bool: no\r\n title_column: org_sla_plan_id\r\n colors:\r\n reds5@csv: #a50f15, #de2d26, #fb6a4a, #fcae91, #fee5d9\r\ncolumns:\r\n card/org_sla_plan_id:\r\n params:\r\n text_size@raw: {{sla_deadline < 'now'|date('U') ? '225%' : '150%'}}\r\n underline@bool: no\r\n bold@bool: yes\r\n text_color@raw: {{sla_deadline < 'now'|date('U') ? 'reds5:2' : ''}}\r\n icon:\r\n image_template@raw: {{sla_deadline < 'now'|date('U') ? 'warning-sign' : ''}}\r\n text/sla_deadline:\r\n params:\r\n bold@raw: {{sla_deadline < 'now'|date('U') ? 'yes' : ''}}\r\n text_color@raw: {{sla_deadline < 'now'|date('U') ? 'reds5:2' : ''}}\r\n value_template@raw:\r\n Due: {{sla_deadline|date('D, d M Y h:ia T')}} ({{sla_deadline|date_pretty}})",
"toolbar_kata": ""
},
"options_kata": "hidden@bool: {{not record_sla_deadline}}"
}
]
}