Skip to content

Ticket Crons

Automated background jobs that manage ticket lifecycle transitions, client notifications, and CSAT survey delivery for support tickets.

Overview

The Ticket Crons module contains three scheduled jobs that automate different stages of the ticket lifecycle. These crons handle scenarios where tickets require automatic status changes, client follow-up reminders, or internal team alerts — all without manual intervention from the support team.

The three crons work together to ensure tickets don't remain in limbo: incomplete tickets get reminders and eventually auto-close, delivered-shipment tickets auto-resolve, and follow-up tickets trigger internal SLA alerts.

Key Concepts

ConceptDescription
Incomplete TicketA ticket the client started creating but never finished submitting (status = INCOMPLETE)
Follow-Up TicketA ticket awaiting a response from the support team for more than 24 hours (status = FOLLOW_UP)
AutocloseAutomatic resolution of tickets whose associated shipment was delivered, making the ticket no longer relevant
CSATCustomer Satisfaction survey sent via email, WhatsApp, and in-platform notification after a ticket is closed
Claim TypesTicket types that involve a formal claim: Lost, Theft, Damaged, Overweight, Irregular Package
Delivery TypesTicket types auto-closed on delivery: Shipment Created Without Changes, Delay, Redirection, Delivery Attempt

Cron Summary

CronRouteTriggerWhat It Does
notifyFollowUpAndIncompleteTicketsGET /notify/tickets/follow-up-incompletePeriodicSends reminders to clients with incomplete tickets; sends Slack SLA alerts for follow-up tickets
notifyAutocloseTicketsGET /notify/tickets/autoclosePeriodicAuto-accepts tickets whose shipment was delivered and sends CSAT surveys
closeTicketsIncompleteGET /notify/tickets/incompletePeriodicAuto-declines claim tickets that remained incomplete for 10+ days and sends CSAT surveys

Data Flow

Cron 1: notifyFollowUpAndIncompleteTickets

Cron 2: notifyAutocloseTickets

Cron 3: closeTicketsIncomplete

Detailed Behavior

notifyFollowUpAndIncompleteTickets

Query criteria:

  • Ticket status is INCOMPLETE (4) or FOLLOW_UP (5)
  • Created on or after 2025-05-12
  • Company locale is not India (locale_id ≠ 11)

For incomplete tickets, the cron sends a multi-channel reminder:

ChannelContent
EmailPersonalized message with ticket ID, ticket type, and a link to /settings/tickets
Platform notificationGlobal notification with the last admin comment as context
Ticket commentPersonalized message per ticket type (e.g., "Your lost package claim is incomplete")
WhatsAppNotification via queue with ticket status context

The personalized message varies by ticket type using translation keys:

Ticket TypeTranslation Key
Delaynotification.ticket.incomplete.delay
Redirectionnotification.ticket.incomplete.redirection
Wrong Addressnotification.ticket.incomplete.wrong_address
Shipment Created Without Changesnotification.ticket.incomplete.shipment_created_without_changes
Overweightnotification.ticket.incomplete.overweight
Lostnotification.ticket.incomplete.lost
Damagednotification.ticket.incomplete.damaged
Theftnotification.ticket.incomplete.theft

For follow-up tickets, the cron sends a Slack alert to #alert-cs-tickets with:

  • Company name, ticket type, ticket status
  • Time without attention indicator ("+24 hours")
  • Last client comment
  • SLA compliance message

notifyAutocloseTickets

Query criteria:

  • Ticket type is one of: Shipment Created Without Changes (12), Delay (8), Redirection (14), Delivery Attempt (25)
  • Ticket status is NOT Accepted, Declined, or Claim In Review
  • Associated shipment status is Delivered or Delivered at Origin

Actions per ticket:

  1. Updates ticket status to ACCEPTED (2)
  2. Inserts a translated "delivered" comment
  3. Records status change in ticket history
  4. Sends CSAT notifications (platform rating + email + WhatsApp)

closeTicketsIncomplete

Query criteria:

  • Ticket status is INCOMPLETE (4)
  • Last updated 10+ days ago (utc_updated_at ≤ UTC_TIMESTAMP() - INTERVAL 10 DAY)
  • Ticket type is a claim type: Lost (4), Theft (13), Damaged (5), Overweight (3), Irregular Package (21)
  • Company locale is not India (locale_id ≠ 11)

Actions:

  1. Bulk updates all matching tickets to DECLINED (3)
  2. Batch inserts history records for all tickets
  3. For each ticket individually:
    • Looks up the user to notify (ticket creator or company owner)
    • Generates a personalized close message per ticket type
    • Inserts a ticket comment with the close message
    • Sends CSAT notifications (platform rating + email + WhatsApp)

The close message varies by ticket type using translation keys:

Ticket TypeTranslation Key
Delaynotification.ticket.in_analysis.delay
Redirectionnotification.ticket.in_analysis.redirection
Wrong Addressnotification.ticket.in_analysis.wrong_address
Shipment Created Without Changesnotification.ticket.in_analysis.shipment_created_without_changes
Overweightnotification.ticket.in_analysis.overweight
Lostnotification.ticket.in_analysis.lost
Damagednotification.ticket.in_analysis.damaged
Theftnotification.ticket.in_analysis.theft

If the ticket type has no specific message, a generic fallback is used: notification.ticket.in_analysis.content_platform.

CSAT Notification Pipeline

When a ticket is closed (by autoclose or auto-decline), the sendTicketCsatNotifications function dispatches three notifications in parallel:

India locale (locale_id = 11) is excluded from all CSAT notifications.

Database

Tables

TablePurpose
company_ticketsMain ticket table with status, type, company, shipment, and timestamps
company_ticket_historyAudit log of all ticket status changes
company_ticket_commentsComments on tickets (client and admin messages)
catalog_ticket_typesTicket type catalog with descriptions and translation tags
catalog_ticket_statusesTicket status catalog with slugs and descriptions
companiesCompany data including locale
localesLocale configuration with language and currency
shipmentsShipment data used for autoclose delivery checks

Key Relationships

Key Decisions

DecisionReasoningAlternatives Considered
setImmediate for all cronsReturns HTTP 200 immediately to the cron scheduler, then processes tickets asynchronously to avoid timeouts on large batchesSynchronous processing (risk of HTTP timeout), Bull queue (unnecessary complexity for periodic jobs)
Bulk update + batch insert for closeTicketsIncompleteEfficient single SQL statements for status change and history instead of N individual updatesIndividual updates per ticket (slower, more DB round-trips)
Promise.allSettled for notificationsOne notification failure should not prevent others from being sentPromise.all (one failure cancels all), sequential (slower)
India locale exclusionIndia operations have a separate CSAT process; platform CSAT should not overlapNo exclusion (duplicate surveys), config-based exclusion (over-engineering)
Personalized messages per ticket typeEach claim type has a different context; generic messages reduce client understandingSingle generic message (less helpful), per-ticket custom text (not scalable)
Translation keys stored in DBContent team can update message wording without code changesHardcoded strings (requires deployments for text changes)

Dependencies

  • Internal: ticketsV2.util.js (notification logic, message generation), companies.util.js (ticket comments, rating notifications), notifications service (email, WhatsApp, Slack, platform), translate.util.js (i18n)
  • External: Mailgun (email delivery), WhatsApp queue (message delivery), Slack API (team alerts)
  • API Endpoints — Cron route definitions and authentication
  • User Guide — Non-technical overview of ticket automation

Envia Admin