Issue 301 CSAT Delay Was Never Applied - edmozley/freeitsm GitHub Wiki
๐ #301 CSAT "Delay before sending" was saved but never applied
GitHub #301, reported by Abdullah31H ยท Tickets, CSAT ยท fixed in 5.0.0 (#2783)
What you saw
Tickets โ Settings โ CSAT has a Delay before sending (minutes), and its help says what it is for - give the requester time to see the fix held before asking them to rate it. Set it to 30, close a ticket, and the survey arrived straight away.
What was wrong
The setting was saved and shown back, and read by nothing. The close path called sendCsatSurvey() directly whenever CSAT was on Auto. There was no queue and no background job - the "or after csat_delay_minutes" in Database Verify's own comment had never been built.
The fix
| Queue on close | csatAutoOnClose() (called by TicketsService when a ticket closes): no delay โ send now, exactly as before; a delay โ a row in csat_queue, one per ticket, due after the delay. |
| A background job | cron/csat_delayed.php - Delayed satisfaction surveys on Reporting โ System logs โ Background jobs - runs every 5 minutes through the built-in scheduler, so there is nothing to set up. It is "needed" only while a delay is set or a survey is waiting, so an install without a delay never sees it overdue. |
| Only if still closed | Due surveys are sent only if the ticket is still closed and not in the trash. Reopened in the meantime โ no survey. Closed again โ queued afresh, and the wait starts over (one row per ticket, so the second close moves it). |
| Never twice | The job claims each row by deleting it before sending; a second overlapping run finds nothing to take. |
| A working link | The survey link used the web request's host name - from a background job, localhost or a bare path. It now uses the public web address when one is configured, and otherwise the address the ticket was closed from, saved with the queued survey. |
Nothing changes for an install with no delay (the default), and a survey can never be lost to the queue: if the queue cannot be written (before Database Verify, say) the survey is sent at once.
๐ Files
| File | Change |
|---|---|
includes/csat.php |
csatAutoOnClose(), csatSendDue(), csatUseLinkBase(); the link through publicAbsoluteUrl(); a resettable settings cache |
includes/services/tickets.php |
the close path calls csatAutoOnClose() |
cron/csat_delayed.php |
new background job |
includes/job_registry.php |
the job registered, tied to the CSAT switch |
database/freeitsm.sql, includes/db_verify_schema.php, includes/db_verify_indexes.php |
csat_queue (unique per ticket) |
includes/analyst_lifecycle.php, includes/db_verify_modules.php |
the new table's analyst column and its DB Verify group |
lang/{en,de,es}/tickets.php, reporting.php |
the delay's help says what a reopen does; the job's name |
How it was proved
tests/csat-delay.php, 15 checks on a throwaway install. It sends no mail: every CSAT email template is switched off for the run, so the send stops at its "no template" check - proof the job reached the send, with nothing leaving the building. A 30-minute delay queues the survey due in 30 minutes and sends nothing; the job leaves it alone until due, then takes it; a ticket reopened before then gets no survey; a second close keeps one row and moves it; no delay queues nothing; the job is needed only while a delay is set; the link uses the address the ticket was closed from, and a configured address always wins. The background-job health (35) and scheduler (38) suites still pass.
What this means for you
- Using a delay? It works from 5.0.0 - run Database Verify after upgrading. The built-in scheduler starts the new job; if you run jobs from your own scheduled tasks instead, add
cron/csat_delayed.phpevery 5 minutes. - Not using one? Nothing changes.
- Set your public web address (System โ Settings) so every emailed link - surveys included - uses it.
And the reminder the issue suggested (#2784)
The report also suggested an optional reminder for surveys nobody answers. Built as suggested, under Tickets โ Settings โ CSAT:
- Send one reminder if the survey is not answered, with Remind after (hours) - 1 to 336 (two weeks), 48 by default. Off by default, so an upgrade changes nothing.
- At most one per survey:
ticket_csat_responses.reminder_sent_datetimeis set by an update only one run can win, before the email goes. - The same link (the same token), so the survey and the reminder both work and only one rating is stored.
- Email only - a survey asked in a chat has its own seven-day reply window.
- Not if the ticket has been reopened or trashed, or CSAT switched off.
- Switching it on never mails old surveys: only those whose reminder falls due from the moment it is switched on (
csat_reminder_since, changelog #2798 - at first it allowed any whose reminder had fallen due in the previous 48 hours, which could send a burst on the day it was ticked). A job that was down for days still catches up with no more than 48 hours (CSAT_REMINDER_CATCHUP_HOURS). - The email is the new CSAT reminder template event (Tickets โ Settings โ Email templates) when there is one, otherwise the survey template again. With neither, nothing is claimed - a reminder marked sent when nothing could go would be lost.
It is sent by the same background job, now Delayed satisfaction surveys and reminders, which the built-in scheduler already runs every 5 minutes. The reminder's link uses the address the survey was sent from (ticket_csat_responses.link_base) when no public address is configured.
Proved by tests/csat-delay.php (now 24 checks) with a stand-in sender, so nothing is mailed: off by default; no template, nothing claimed; on, exactly one reminder - for the unanswered emailed survey just due - and not for one too young, one long overdue, an answered one or a chat one; the reminder template and the same link; never a second; none after a reopen.