Development of a 1C-Bitrix ticketing system module

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1173
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    745
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Developing a Ticket System Module for 1C-Bitrix

Email-based support works as long as there is only one support agent. Once there are two or more, problems start: duplicate responses, lost emails, inability to track conversation history for specific issues, lack of SLA. The built-in Helpdesk in Bitrix24 solves the problem, but requires a separate license. For a site on 1C-Bitrix with its own personal account, you need your own ticket system integrated with user profiles and orders.

Data Model

Module vendor.tickets:

  • b_vendor_ticket — tickets: id, number (human-readable, T-2024-0001), user_id, subject, status (open/pending/resolved/closed), priority (low/normal/high/urgent), category_id, assigned_to (agent_id), order_id (optional), first_response_at, resolved_at, created_at, updated_at
  • b_vendor_ticket_message — ticket messages: id, ticket_id, author_id, author_type (user/agent/system), body, is_internal (internal note), created_at
  • b_vendor_ticket_attachment — files: id, message_id, file_id
  • b_vendor_ticket_category — categories: id, name, sort, default_assigned_to, sla_hours
  • b_vendor_ticket_sla_breach — SLA breaches: id, ticket_id, breach_type (first_response/resolution), breached_at

Creating a Ticket by User

class TicketService
{
    public function create(int $userId, array $data): CreateResult
    {
        $number = $this->generateNumber(); // T-2024-0001, atomic counter

        $category = CategoryTable::getById($data['category_id'])->fetch();

        $ticketId = TicketTable::add([
            'NUMBER'      => $number,
            'USER_ID'     => $userId,
            'SUBJECT'     => $data['subject'],
            'STATUS'      => 'open',
            'PRIORITY'    => $data['priority'] ?? 'normal',
            'CATEGORY_ID' => $data['category_id'],
            'ASSIGNED_TO' => $category['DEFAULT_ASSIGNED_TO'],
            'ORDER_ID'    => $data['order_id'] ?? null,
        ])->getId();

        // First message
        MessageTable::add([
            'TICKET_ID'   => $ticketId,
            'AUTHOR_ID'   => $userId,
            'AUTHOR_TYPE' => 'user',
            'BODY'        => $data['message'],
        ]);

        // Notify support agent
        $this->notifyAgent($ticketId);

        return CreateResult::success($ticketId);
    }
}

Conversation in the Ticket

Each subsequent message is a new record in b_vendor_ticket_message. Agents can leave internal notes (is_internal = 1) that the user cannot see, but other agents can. When an agent replies:

  • Ticket status changes to pending (waiting for user response)
  • first_response_at is recorded (if this is the first response)
  • User receives an email notification

When a user replies:

  • Status changes to open
  • Agent receives notification

SLA Control

SLA is set at the category level (sla_hours). An agent checks every 15 minutes:

public static function checkSlaBreaches(): void
{
    $breachTime = (new DateTime())->modify("-{$category['SLA_HOURS']} hours");

    $overdue = TicketTable::getList([
        'filter' => [
            'STATUS'           => 'open',
            '<=CREATED_AT'     => $breachTime,
            'FIRST_RESPONSE_AT' => false, // no first response
        ],
    ])->fetchAll();

    foreach ($overdue as $ticket) {
        SlaBreachTable::add([
            'TICKET_ID'   => $ticket['ID'],
            'BREACH_TYPE' => 'first_response',
            'BREACHED_AT' => new DateTime(),
        ]);
        // Notify support manager
        $this->notifySlaManager($ticket);
    }
}

Agent Assignment and Queues

  • Auto-assignment: when a ticket is created, the agent is selected by category (field default_assigned_to)
  • Load balancing: if multiple agents are in the queue, the one with fewer open tickets is selected
  • Manual reassignment: an agent can transfer the ticket to a colleague with a reason specified

Support Quality Rating

After moving the ticket to resolved, the user is sent a link to rate the support:

GET /support/rate/?ticket=T-2024-0001&token=abc123&score=5

The token is one-time, with a 7-day lifespan. Ratings are aggregated into a CSAT metric by agent and by category.

Personal Account and Administrative Interface

User: list of their tickets, statuses, conversation, create new ticket, attach file.

Support Agent: incoming tickets (their queue + unassigned), filter by priority/category/status, quick replies (templates), internal notes, change history.

Manager: dashboard — average response time, CSAT by agents, number of SLA breaches, load by agents.

Development Timeline

Stage Duration
ORM-tables, number generator 1 day
Creating tickets, conversation 2 days
SLA-control, monitoring agent 2 days
Agent assignment, load balancing 1 day
CSAT rating, tokens 1 day
User personal account 2 days
Support agent interface 3 days
Manager dashboard 1 day
Testing 1 day

Total: 14 working days. Email-to-ticket (create ticket from incoming email) — additional 2 days.