GuideOdoo HelpdeskMarch 13, 2026

Helpdesk SLA Policies in Odoo 19:
Ticket Automation & Customer Satisfaction

INTRODUCTION

Your Helpdesk Is Losing Customers Without You Knowing It

Here is the pattern we see at every mid-market company running support out of shared inboxes and spreadsheets: a customer emails about a billing issue on Monday. Nobody owns it. By Wednesday the customer emails again, CC'ing their account manager. By Friday they are evaluating your competitor. You never breached a contract — you just never defined what "on time" meant.

Odoo 19's Helpdesk module solves this with SLA policies — enforceable time-based rules that define how quickly your team must respond to, and resolve, every ticket based on its priority, type, and customer tier. When an SLA deadline approaches, Odoo escalates automatically. When it's breached, the ticket turns red and managers get notified. No spreadsheet can do that.

This guide covers everything from initial helpdesk team configuration through SLA policy design, ticket stage automation, assignment rules, email gateway integration, customer portal setup, CSAT surveys, after-sales service linking, and the reporting dashboards that tell you whether your support operation is actually working. Every field name and menu path is from Odoo 19 Enterprise.

01

Configuring Helpdesk Teams in Odoo 19: Channels, Visibility, and Assignment Methods

Before you create a single SLA policy, you need a properly structured helpdesk team. Navigate to Helpdesk → Configuration → Helpdesk Teams and create your first team. The configuration choices you make here determine how tickets flow through your entire support operation.

FieldPurposeOur Recommendation
nameTeam display name shown in ticket views and portalUse functional names: "Billing Support", "Technical Support", not "Team A"
alias_idEmail alias that auto-creates tickets (e.g., support@yourcompany.com)One alias per team — never route all emails to a single catchall
assign_methodHow new tickets are assigned: Manual, Random, BalancedBalanced — distributes by current open ticket count per agent
member_idsTeam members eligible for ticket assignmentOnly include agents who are actively handling tickets — not managers
use_slaEnable SLA tracking on this teamAlways enable — even internal teams benefit from response time tracking
use_ratingEnable customer satisfaction surveys on ticket closeEnable for all external-facing teams

Email Gateway Configuration

The email alias is the primary ticket creation channel for most teams. When a customer sends an email to support@yourcompany.com, Odoo creates a helpdesk.ticket record with the email subject as the ticket name, the body as the description, and the sender matched to an existing res.partner via email lookup. To configure it, go to Settings → Technical → Email → Aliases or set it directly on the team form under the Channels tab.

Python — Custom ticket creation hook via email gateway
from odoo import models, api

class HelpdeskTicket(models.Model):
    _inherit = 'helpdesk.ticket'

    @api.model_create_multi
    def create(self, vals_list):
        """Auto-set priority based on partner's SLA tier tag."""
        for vals in vals_list:
            if vals.get('partner_id') and not vals.get('priority'):
                partner = self.env['res.partner'].browse(
                    vals['partner_id']
                )
                # Check for VIP tag on the contact
                vip_tag = self.env.ref(
                    'my_helpdesk.partner_tag_vip', raise_if_not_found=False
                )
                if vip_tag and vip_tag in partner.category_id:
                    vals['priority'] = '3'  # Urgent
                elif partner.parent_id and partner.parent_id.is_company:
                    # Enterprise customers get High priority by default
                    contract = self.env['sale.order'].search([
                        ('partner_id', '=', partner.parent_id.id),
                        ('state', '=', 'sale'),
                        ('tag_ids.name', 'ilike', 'Premium Support'),
                    ], limit=1)
                    if contract:
                        vals['priority'] = '2'  # High
        return super().create(vals_list)
Assignment Method Matters More Than You Think

Random assignment ignores workload — an agent with 30 open tickets gets the same chance as one with 5. Balanced counts current open tickets per member and assigns to the least loaded agent. For teams larger than 3 agents, Balanced reduces average first response time by 25-40% in our measurements, because tickets stop piling up on whoever happened to be assigned three urgent ones in a row.

02

Designing SLA Policies in Odoo 19: Response Time, Resolution Time, and Priority Escalation

SLA policies are the backbone of a professional support operation. In Odoo 19, navigate to Helpdesk → Configuration → SLA Policies to create them. Each policy defines a target stage and a time limit — if the ticket doesn't reach that stage within the allotted time, the SLA is marked as failed.

A well-designed SLA matrix uses two policies per priority level: one for first response (reaching the "In Progress" stage) and one for resolution (reaching the "Solved" stage). Here is the matrix we deploy for most mid-market clients:

PriorityFirst Response TargetResolution TargetBusiness Hours Only
Urgent (3)30 minutes4 hoursNo (24/7)
High (2)2 hours8 hoursYes
Medium (1)4 hours24 hoursYes
Low (0)8 hours48 hoursYes
XML — SLA policy data records for deployment
<odoo>
  <data noupdate="1">

    <!-- ── First Response SLAs ────────────────────── -->
    <record id="sla_urgent_response" model="helpdesk.sla">
      <field name="name">Urgent — First Response (30 min)</field>
      <field name="team_id" ref="helpdesk.helpdesk_team1"/>
      <field name="priority">3</field>
      <field name="stage_id" ref="helpdesk.stage_in_progress"/>
      <field name="time">0.5</field>
      <!-- time is in hours; 0.5 = 30 minutes -->
      <field name="exclude_stage_ids"
             eval="[(6, 0, [])]"/>
    </record>

    <record id="sla_urgent_resolution" model="helpdesk.sla">
      <field name="name">Urgent — Resolution (4 hrs)</field>
      <field name="team_id" ref="helpdesk.helpdesk_team1"/>
      <field name="priority">3</field>
      <field name="stage_id" ref="helpdesk.stage_solved"/>
      <field name="time">4</field>
    </record>

    <record id="sla_high_response" model="helpdesk.sla">
      <field name="name">High — First Response (2 hrs)</field>
      <field name="team_id" ref="helpdesk.helpdesk_team1"/>
      <field name="priority">2</field>
      <field name="stage_id" ref="helpdesk.stage_in_progress"/>
      <field name="time">2</field>
    </record>

    <record id="sla_high_resolution" model="helpdesk.sla">
      <field name="name">High — Resolution (8 hrs)</field>
      <field name="team_id" ref="helpdesk.helpdesk_team1"/>
      <field name="priority">2</field>
      <field name="stage_id" ref="helpdesk.stage_solved"/>
      <field name="time">8</field>
    </record>

    <record id="sla_medium_response" model="helpdesk.sla">
      <field name="name">Medium — First Response (4 hrs)</field>
      <field name="team_id" ref="helpdesk.helpdesk_team1"/>
      <field name="priority">1</field>
      <field name="stage_id" ref="helpdesk.stage_in_progress"/>
      <field name="time">4</field>
    </record>

    <record id="sla_medium_resolution" model="helpdesk.sla">
      <field name="name">Medium — Resolution (24 hrs)</field>
      <field name="team_id" ref="helpdesk.helpdesk_team1"/>
      <field name="priority">1</field>
      <field name="stage_id" ref="helpdesk.stage_solved"/>
      <field name="time">24</field>
    </record>

  </data>
</odoo>

How SLA Deadlines Are Calculated

Odoo 19 calculates SLA deadlines using the resource.calendar assigned to the helpdesk team. If your team's working hours are Monday–Friday 9:00–17:00, a ticket created at 16:30 on Friday with a 2-hour first response SLA has a deadline of Monday at 10:30, not Saturday at 18:30. The field sla_deadline on helpdesk.ticket stores the computed datetime. The boolean sla_fail flips to True when the current time exceeds the deadline and the ticket hasn't reached the target stage.

Two SLAs, Not One

Most teams create a single SLA for "resolution time" and call it done. This misses the most important metric: first response time. A customer who gets acknowledged within 30 minutes will tolerate a 24-hour resolution. A customer who hears nothing for 4 hours assumes you don't care — even if you resolve the issue in 5 hours total. Always pair a response SLA (target stage: In Progress) with a resolution SLA (target stage: Solved).

03

Ticket Automation in Odoo 19: Stage Transitions, Escalation Rules, and Scheduled Actions

SLA policies define deadlines. Automation enforces them. Odoo 19 provides three automation mechanisms for helpdesk tickets: automated actions (server actions triggered by field changes), scheduled actions (cron-based), and mail templates tied to stage transitions. Together, these replace the manual monitoring that burns out support managers.

Ticket Stage Pipeline

Define your stages under Helpdesk → Configuration → Stages. The stage sequence controls the Kanban column order. A standard pipeline for most support teams looks like this:

StageSequenceFold in KanbanPurpose
New1NoIncoming tickets, not yet triaged
In Progress2NoAgent is actively working — triggers "first response" SLA
Waiting on Customer3NoAgent requested info, SLA clock should pause
Solved4YesResolution confirmed — triggers CSAT survey
Cancelled5YesDuplicate, spam, or customer withdrew request
Python — Automated escalation action for SLA-breached tickets
from odoo import models, fields, api
from datetime import timedelta

class HelpdeskSLAEscalation(models.Model):
    _inherit = 'helpdesk.ticket'

    is_escalated = fields.Boolean(
        string='Escalated',
        default=False,
        tracking=True,
    )
    escalation_date = fields.Datetime(
        string='Escalation Date',
        readonly=True,
    )

    def _cron_escalate_sla_breached(self):
        """Scheduled action: escalate tickets that breached SLA.

        Run every 15 minutes via ir.cron.
        Menu: Settings → Technical → Automation → Scheduled Actions
        """
        breached_tickets = self.search([
            ('sla_fail', '=', True),
            ('is_escalated', '=', False),
            ('stage_id.fold', '=', False),  # Not in closed stages
        ])
        manager_group = self.env.ref('helpdesk.group_helpdesk_manager')
        managers = manager_group.users

        for ticket in breached_tickets:
            ticket.write({
                'is_escalated': True,
                'escalation_date': fields.Datetime.now(),
                'priority': str(min(int(ticket.priority) + 1, 3)),
            })
            # Post internal note visible only to agents
            ticket.message_post(
                body=(
                    f'<strong>SLA Breached — Auto-Escalated</strong>'
                    f'<br/>Priority raised to '
                    f'{{ticket.priority}}. '
                    f'Original deadline: '
                    f'{{ticket.sla_deadline}}'
                ),
                message_type='comment',
                subtype_xmlid='mail.mt_note',
                partner_ids=managers.mapped('partner_id').ids,
            )

    def _cron_auto_close_stale_tickets(self):
        """Close tickets stuck in 'Waiting on Customer' for 7+ days.

        Sends a final notification before closing.
        """
        stale_date = fields.Datetime.now() - timedelta(days=7)
        waiting_stage = self.env.ref(
            'my_helpdesk.stage_waiting_customer',
            raise_if_not_found=False,
        )
        solved_stage = self.env.ref(
            'helpdesk.stage_solved',
            raise_if_not_found=False,
        )
        if not waiting_stage or not solved_stage:
            return

        stale_tickets = self.search([
            ('stage_id', '=', waiting_stage.id),
            ('write_date', '<=', stale_date),
        ])
        for ticket in stale_tickets:
            ticket.write({'stage_id': solved_stage.id})
            ticket.message_post(
                body=(
                    'This ticket was automatically closed after '
                    '7 days without customer response. '
                    'Please reopen if you still need assistance.'
                ),
                message_type='comment',
                subtype_xmlid='mail.mt_comment',
            )

Setting Up the Scheduled Actions

Navigate to Settings → Technical → Automation → Scheduled Actions and create two entries:

  • Escalate SLA-Breached Tickets — Model: helpdesk.ticket, Method: _cron_escalate_sla_breached, Interval: 15 minutes.
  • Auto-Close Stale Tickets — Model: helpdesk.ticket, Method: _cron_auto_close_stale_tickets, Interval: 1 day.
SLA Clock Pausing on "Waiting on Customer"

In Odoo 19, you can exclude specific stages from SLA time calculation by adding them to the exclude_stage_ids field on the SLA policy record. When a ticket enters an excluded stage, the SLA clock pauses. When it leaves, the clock resumes. Always exclude your "Waiting on Customer" stage — otherwise every customer who takes 2 days to reply causes an SLA breach that isn't your team's fault.

04

Customer Portal, CSAT Surveys, and After-Sales Service Integration in Odoo 19

The helpdesk module's value extends beyond your internal team. Odoo 19 provides a customer portal where clients can submit tickets, track progress, and view their history — and a CSAT rating system that collects satisfaction data automatically when tickets close.

Portal Ticket Submission

Enable the portal under Helpdesk → Configuration → Helpdesk Teams → [Your Team] → Help Center. Toggle Website Form to let portal users submit tickets via /helpdesk/[team-slug]/submit. Portal users see only their own tickets, can add messages, and can close resolved tickets directly. The portal view respects ir.rule record rules — customers never see other customers' tickets.

CSAT Rating Configuration

Enable Customer Ratings on the team form. When a ticket moves to a closing stage (any stage with is_close = True), Odoo sends a rating email with a 3-point scale: satisfied (green), okay (yellow), dissatisfied (red). The rating is stored on the rating.rating model linked to the ticket. You can view aggregate scores at Helpdesk → Reporting → Customer Ratings.

XML — Custom CSAT email template with ticket details
<odoo>
  <data>
    <record id="rating_ticket_email_custom" model="mail.template">
      <field name="name">Helpdesk: Custom CSAT Survey</field>
      <field name="model_id" ref="helpdesk.model_helpdesk_ticket"/>
      <field name="subject">How did we do? Ticket #{{object.id}} — {{object.name}}</field>
      <field name="email_from">{{object.team_id.alias_id.display_name}}</field>
      <field name="email_to">{{object.partner_id.email}}</field>
      <field name="body_html" type="html">
        <div style="margin: 0; padding: 0;">
          <p>Hello {{object.partner_id.name}},</p>
          <p>
            Your support ticket <strong>#{{object.id}} —
            {{object.name}}</strong> has been resolved
            by {{object.user_id.name}}.
          </p>
          <p>How would you rate your experience?</p>
          <t t-set="access_token"
             t-value="object._rating_get_access_token()"/>
          <table style="margin: 20px 0; border-spacing: 12px;">
            <tr>
              <td>
                <a t-attf-href="/rate/{{access_token}}/5"
                   style="text-decoration: none; font-size: 32px;"
                >🙂</a>
                <br/>Satisfied
              </td>
              <td>
                <a t-attf-href="/rate/{{access_token}}/3"
                   style="text-decoration: none; font-size: 32px;"
                >😐</a>
                <br/>Okay
              </td>
              <td>
                <a t-attf-href="/rate/{{access_token}}/1"
                   style="text-decoration: none; font-size: 32px;"
                >😞</a>
                <br/>Dissatisfied
              </td>
            </tr>
          </table>
          <p style="color: #888; font-size: 12px;">
            Resolved in {{object.sla_status_ids[0].reached_datetime}}
            by team {{object.team_id.name}}.
          </p>
        </div>
      </field>
    </record>
  </data>
</odoo>

After-Sales Service Integration

Odoo 19 links helpdesk tickets to sales orders, subscriptions, and product lots via the sale_order_id, subscription_id, and lot_id fields on helpdesk.ticket. Enable this under Helpdesk → Configuration → Settings → After-Sales. When enabled, agents can see the customer's purchase history, warranty status, and active subscriptions directly from the ticket form — no tab-switching required.

  • Refunds — agents can create credit notes directly from the ticket via the Refund button.
  • Returns — agents can initiate a reverse transfer linked to the original delivery order.
  • Coupons — agents can generate a discount coupon as a goodwill gesture, tracked on the ticket.
  • Repair Orders — if the Repair module is installed, agents can create repair orders linked to the ticket's product lot.
CSAT Response Rates

The average CSAT email response rate is 8-12%. To improve it: send the survey immediately on ticket close (not 24 hours later — by then the customer has moved on), keep the email under 100 words, and make the rating a single click with no login required. Odoo's rating access tokens handle this natively — the customer clicks the emoji and the rating is recorded without authentication.

05

Helpdesk Reporting Dashboards: SLA Performance, Agent Load, and Trend Analysis

Data without dashboards is just noise. Odoo 19's helpdesk module includes built-in reporting under Helpdesk → Reporting with four views: Ticket Analysis, SLA Status Analysis, Customer Ratings, and Team Performance. Each view supports pivot tables, charts, and custom filter combinations.

ReportKey MetricsWho Uses It
Ticket AnalysisVolume by channel, avg. resolution time, tickets by stageSupport managers — weekly capacity planning
SLA Status AnalysisSLA success rate, avg. time to target stage, breaches by priorityOperations leads — SLA compliance reporting
Customer RatingsCSAT score by agent, team, and time periodTeam leads — agent performance reviews
Team PerformanceTickets per agent, first response time, resolution timeSupport managers — workload balancing
Python — Custom dashboard domain for SLA breach report
from odoo import models, fields

class HelpdeskSLAReport(models.Model):
    _inherit = 'helpdesk.sla.report.analysis'

    breach_hours = fields.Float(
        string='Hours Over SLA',
        compute='_compute_breach_hours',
        store=True,
    )

    @api.depends('sla_deadline', 'sla_reached_datetime')
    def _compute_breach_hours(self):
        for record in self:
            if record.sla_fail and record.sla_deadline:
                reached = (
                    record.sla_reached_datetime
                    or fields.Datetime.now()
                )
                delta = reached - record.sla_deadline
                record.breach_hours = delta.total_seconds() / 3600
            else:
                record.breach_hours = 0.0

For executive reporting, create a custom Spreadsheet Dashboard under Dashboards → Spreadsheet that pulls from the helpdesk pivot views. The most useful executive view combines: weekly ticket volume trend, SLA compliance percentage (target: above 90%), average first response time, and CSAT score. Share the spreadsheet with your leadership team and set it as their Odoo home action.

06

3 Helpdesk Configuration Mistakes That Tank Your SLA Compliance Rate

1

Not Excluding "Waiting on Customer" from SLA Calculation

This is the most common SLA configuration mistake we encounter. Your agent responds within 15 minutes and moves the ticket to "Waiting on Customer." The customer takes 3 days to reply. The SLA clock kept running the entire time, so now your 8-hour resolution SLA shows as breached by 64 hours — even though your team did everything right. Managers see a 40% SLA failure rate and blame the team when the real culprit is the clock configuration.

Our Fix

On every SLA policy record, add your "Waiting on Customer" stage to the exclude_stage_ids many2many field. In Odoo 19, navigate to the SLA policy form and use the Excluding Stages field. This pauses the SLA clock when the ticket enters that stage and resumes it when the ticket moves forward. Apply this to every SLA policy — it is easy to forget when you create new ones.

2

Using a Single SLA Policy for All Priority Levels

Some teams create one SLA — "Resolve within 24 hours" — and apply it to every ticket regardless of priority. The result: urgent production-down tickets and low-priority feature requests have the same deadline. Agents learn to ignore the SLA because everything is equally urgent, which means nothing is. The SLA metric becomes meaningless noise, and the team reverts to gut-feel triage.

Our Fix

Create separate SLA policies per priority level with progressively tighter deadlines. Use the priority field on the SLA record to filter. Urgent tickets get 30-minute response; low-priority gets 8 hours. This gives agents a clear signal about what to work on next without manual manager intervention.

3

No Working Hours Calendar Assigned to the Helpdesk Team

Without a resource.calendar linked to the team, SLA deadlines are calculated on a 24/7 basis. A ticket created at 17:01 on Friday with a 4-hour SLA gets a deadline of 21:01 Friday — when nobody is in the office. The SLA breaches overnight, the manager gets an escalation notification at 6 AM Saturday, and the team starts Monday demoralized by a queue full of red "SLA Failed" badges for tickets that were never actionable on a weekend.

Our Fix

Navigate to Helpdesk → Configuration → Helpdesk Teams → [Your Team] and set the Working Hours field to your team's actual schedule. Create the calendar under Employees → Configuration → Working Schedules if it doesn't exist. Exception: if you offer 24/7 premium support, create a separate team with a 24/7 calendar and route premium customers to it.

BUSINESS ROI

What a Properly Configured Helpdesk Saves Your Business

The helpdesk module is included with Odoo Enterprise. The ROI comes from the operational improvements:

35%Faster First Response

Balanced assignment + SLA escalation rules eliminate the "nobody owned this ticket" problem. Average first response drops from 6 hours to under 2.

90%+SLA Compliance Rate

With proper clock pausing on customer-wait stages and priority-tiered deadlines, teams consistently hit 90%+ SLA compliance within the first quarter.

22%Higher Retention

Companies with sub-2-hour first response and CSAT above 85% see measurably lower churn. The cost of one retained customer exceeds the entire helpdesk setup investment.

Beyond the numbers: SLA data gives you leverage in contract negotiations. When you can show a prospective customer that your support team resolved 93% of tickets within SLA last quarter, that is a sales asset. When renewal time comes, documented CSAT scores above 90% make the pricing conversation about value, not cost.

SEO NOTES

Optimization Metadata

Meta Desc

Complete guide to Odoo 19 Helpdesk SLA policies, ticket automation, CSAT surveys, and reporting. Covers team setup, stage pipeline, escalation rules, and customer portal.

H2 Keywords

1. "Designing SLA Policies in Odoo 19: Response Time, Resolution Time, and Priority Escalation"
2. "Ticket Automation in Odoo 19: Stage Transitions, Escalation Rules, and Scheduled Actions"
3. "3 Helpdesk Configuration Mistakes That Tank Your SLA Compliance Rate"

Stop Running Support Without a Safety Net

Every unanswered ticket is a customer deciding whether you are worth their business. SLA policies turn that invisible risk into a visible, manageable metric. Automated escalation ensures that no ticket falls through the cracks because someone was on lunch. CSAT surveys close the feedback loop so you know — with data, not gut feel — whether your support operation is working.

If you are running Odoo Helpdesk without SLA policies, or if your SLA compliance rate is below 80%, we can help. We audit your helpdesk configuration, design a priority-tiered SLA matrix, implement escalation automation, and set up the reporting dashboards your leadership team needs. The engagement typically takes 2-3 days and pays for itself within the first month of measurable improvement.

Book a Free Helpdesk Audit