Skip to content

Báo cáo (Reports)

Nhóm 9 báo cáo cho module Telesales: dashboard tổng quan, disposition breakdown, hiệu suất agent, funnel, sức khoẻ caller-ID, heatmap giờ × thứ, lead-source attribution, chuỗi thời gian và abandon rate. Tất cả đều hỗ trợ export CSV/Excel.

Query params chung

Mọi endpoint chia sẻ bộ tham số sau (UTC ISO 8601):

FieldTypeRequiredMô tảGiá trị hợp lệ
campaign_idintegeroptionalLọc theo chiến dịch
date_fromdatetimeMốc bắt đầu (ISO 8601 UTC)
date_todatetimeMốc kết thúc (ISO 8601 UTC)Khoảng date_from..date_to ≤ 90 ngày
agent_ids[]array<integer>optionalMảng multi-select agent (?agent_ids[]=25&agent_ids[]=26)
team_idintegeroptionalLọc theo nhóm
timezonestringoptionalGroup theo ngày/giờ dùng timezone nàytên timezone TZDB (UTC, Asia/Ho_Chi_Minh, ...) — default UTC
formatstringoptionalĐịnh dạng responsejson (default) / csv / xlsx (xem 9.2)

Lỗi 422 chung — khoảng vượt 90 ngày:

json
{
  "message": "The given data was invalid.",
  "errors": { "date_to": ["The date_from..date_to range may not exceed 90 days."] }
}

Tổng quan 9 endpoint

EndpointNội dung
GET /api/telesales/reports/dashboardKPI tổng quan: dials, answer rate, AHT, conversion
GET /api/telesales/reports/disposition-breakdownTỷ lệ phần trăm theo từng disposition code
GET /api/telesales/reports/agent-performanceKPI per-agent: calls, conversions, AHT, talk time
GET /api/telesales/reports/funnelFunnel: Lead → Dialled → Connected → Talked > 30 s → Converted
GET /api/telesales/reports/caller-id-healthSức khoẻ caller-ID rotation (ASR, short-call ratio, carrier)
GET /api/telesales/reports/hour-dow-heatmapMatrix 24 giờ × 7 ngày (best calling windows)
GET /api/telesales/reports/lead-source-attributionConversion theo nguồn lead
GET /api/telesales/reports/time-seriesChuỗi thời gian theo ?group_by=day|week|hour
GET /api/telesales/reports/abandon-rateAbandon rate realtime (PDPL/TCPA gate)

9.1 Response mẫu

GET /api/telesales/reports/dashboard?campaign_id=43&date_from=2026-06-01&date_to=2026-06-10

Response fields

FieldTypeMô tảGiá trị hợp lệ
total_dialsintegerTổng số lần quay số trong khoảng thời gian≥ 0
total_answersintegerTổng số cuộc gọi được khách hàng bắt máy≥ 0
answer_rate_pctstringChuỗi decimal (2 chữ số) — total_answers / total_dials × 100"0.00"-"100.00"
avg_talk_time_secstringThời gian đàm thoại trung bình (giây)
total_talk_time_secstringTổng thời gian đàm thoại (giây)
unique_agentsintegerSố agent khác nhau đã quay số trong khoảng≥ 0
pdpl_blocked_countintegerSố cuộc gọi bị PDPL chặn (ngoài giờ cho phép)≥ 0
json
{
  "data": {
    "total_dials":        487,
    "total_answers":      312,
    "answer_rate_pct":   "64.07",
    "avg_talk_time_sec": "184.5",
    "total_talk_time_sec": "57563",
    "unique_agents":       12,
    "pdpl_blocked_count":   5
  }
}

GET /api/telesales/reports/agent-performance?campaign_id=43&date_from=...&date_to=...

Response fields (mỗi item trong data[])

FieldTypeMô tảGiá trị hợp lệ
agent_idintegerID user agent
namestringHọ tên agent
usernamestringTên đăng nhập
dialsintegerSố cuộc đã quay trong khoảng≥ 0
answersintegerSố cuộc khách hàng bắt máy≥ 0
avg_aht_secintegerAHT (Average Handle Time) — thời gian xử lý trung bình mỗi cuộc (giây)≥ 0
conversionsintegerSố cuộc chốt thành công≥ 0
conv_ratenumberconversions / answers × 100 (float, KHÔNG phải string)0-100
json
{
  "data": [
    {
      "agent_id":     3,
      "name":         "Nguyen Van A",
      "username":     "agent01",
      "dials":        152,
      "answers":       98,
      "avg_aht_sec":  191,
      "conversions":   28,
      "conv_rate":   18.42
    },
    {
      "agent_id":     4,
      "name":         "Tran Thi B",
      "username":     "agent02",
      "dials":        140,
      "answers":       86,
      "avg_aht_sec":  176,
      "conversions":   22,
      "conv_rate":   15.71
    }
  ]
}

GET /api/telesales/reports/funnel?campaign_id=43&date_from=...&date_to=...

Trả về mảng phẳng (không phải object lồng {stages, conversion_overall_pct}).

Response fields (mỗi item trong data[])

FieldTypeMô tảGiá trị hợp lệ
stagestringTên bước trong funnelTotal leads / Dialed / Connected / Talked > 30s / Disposed / Converted
countintegerSố lead/cuộc gọi ở bước này≥ 0
json
{
  "data": [
    { "stage": "Total leads",  "count":  487 },
    { "stage": "Dialed",       "count":  312 },
    { "stage": "Connected",    "count":  248 },
    { "stage": "Talked > 30s", "count":  198 },
    { "stage": "Disposed",     "count":  290 },
    { "stage": "Converted",    "count":   78 }
  ]
}

Có 6 stage — gồm cả Disposed. Client tự tính conversion_overall_pct = Converted / Total_leads × 100 từ stage đầu và cuối.

GET /api/telesales/reports/disposition-breakdown?campaign_id=43&date_from=...&date_to=...

Response fields (mỗi item trong data[])

FieldTypeMô tảGiá trị hợp lệ
codestringMã disposition
labelstringNhãn hiển thị
categorystringNhóm kết quảcontact / no_contact / callback / remove
colorstringMã màu UI badge#RRGGBB
countintegerSố cuộc gọi có disposition này≥ 0
pctstringChuỗi decimal 2 chữ số — phần trăm trên tổng cuộc gọi"0.00"-"100.00"
json
{
  "data": [
    {
      "code":     "no_answer",
      "label":    "No Answer",
      "category": "no_contact",
      "color":    "#6B7280",
      "count":     95,
      "pct":      "30.45"
    },
    {
      "code":     "sale",
      "label":    "Sale Success",
      "category": "contact",
      "color":    "#10B981",
      "count":     78,
      "pct":      "25.00"
    }
  ]
}

Mỗi item kèm category + color (UI dùng render badge). pct là chuỗi decimal. Không có wrapper meta: {total_calls} — client tự tính total = sum(count).

GET /api/telesales/reports/caller-id-health?date_from=...&date_to=...

Response fields (mỗi item trong data[])

FieldTypeMô tảGiá trị hợp lệ
cidstringSố caller-ID
display_namestring|nullTên nội bộ
carrierstringNhà mạngviettel / mobifone / vinaphone / vietnamobile / landline / other
cli_typestringLoại sốmobile / fixed_02x / hotline_1900 / hotline_1800 / brandname
pool_statusstringTrạng thái trong rotation poolactive / cooldown / paused / disabled
cooldown_untildatetime|nullLúc hết cooldownISO 8601 UTC
daily_capintegerGiới hạn cuộc/ngày≥ 1
total_callsintegerTổng số cuộc đã gọi trong khoảng≥ 0
answered_callsintegerSố cuộc khách hàng bắt máy≥ 0
asr_pctnumberAnswer-Seizure Ratio (%) — answered/total × 1000-100
acd_secintegerAverage Call Duration — thời lượng đàm thoại trung bình (giây)≥ 0
short_callsintegerSố cuộc dưới ngưỡng "đàm thoại có ý nghĩa"≥ 0
short_call_ratio_pctnumberTỷ lệ cuộc ngắn / tổng0-100
rejected_callsintegerSố cuộc bị từ chối≥ 0
health_statusstringPhân loại sức khoẻhealthy / warning / suspected_block / no_data
health_calls_todayintegerSố cuộc gọi hôm nay (dùng đánh giá cooldown)≥ 0
json
{
  "data": [
    {
      "cid":                  "0900000012",
      "display_name":         "Sales Line 1",
      "carrier":              "viettel",
      "cli_type":             "fixed_02x",
      "pool_status":          "active",
      "cooldown_until":        null,
      "daily_cap":             200,
      "total_calls":           152,
      "answered_calls":         98,
      "asr_pct":                64.5,
      "acd_sec":                121,
      "short_calls":             28,
      "short_call_ratio_pct":   18.4,
      "rejected_calls":           2,
      "health_status":         "healthy",
      "health_calls_today":      87
    }
  ]
}

GET /api/telesales/reports/hour-dow-heatmap?campaign_id=43&date_from=...&date_to=...

Trả về mảng phẳng 168 phần tử (7 ngày × 24 giờ), không lồng theo day-of-week.

Response fields (mỗi item trong data[])

FieldTypeMô tảGiá trị hợp lệ
day_of_weekintegerThứ trong tuần0 = CN, 1 = T2, ..., 6 = T7
hourintegerGiờ trong ngày (theo timezone query param)0-23
dialsintegerSố cuộc đã quay trong slot≥ 0
answeredintegerSố cuộc khách bắt máy≥ 0
answer_rate_pctnumberTỷ lệ bắt máy answered/dials × 1000-100
json
{
  "data": [
    { "day_of_week": 1, "hour": 0, "dials": 0,  "answered": 0,  "answer_rate_pct":  0 },
    { "day_of_week": 1, "hour": 1, "dials": 0,  "answered": 0,  "answer_rate_pct":  0 },
    { "day_of_week": 1, "hour": 9, "dials": 87, "answered": 56, "answer_rate_pct": 64.4 }
  ]
}

Client pivot thành matrix 7 × 24 để render heatmap.

GET /api/telesales/reports/lead-source-attribution?date_from=...&date_to=...

Response fields (mỗi item trong data[])

FieldTypeMô tảGiá trị hợp lệ
sourcestringNguồn lead — lead không có nguồn gom dưới "(unknown)"
total_leadsintegerTổng số lead từ nguồn này trong khoảng≥ 0
dialed_countintegerSố lead đã được quay số≥ 0
contacted_countintegerSố lead khách hàng bắt máy≥ 0
conv_countintegerSố lead chốt thành công≥ 0
conv_rate_pctstringTỷ lệ chuyển đổi conv_count/total_leads × 100 (decimal 2 chữ số)"0.00"-"100.00"
json
{
  "data": [
    {
      "source":           "facebook_lead_ads",
      "total_leads":       240,
      "dialed_count":      230,
      "contacted_count":   152,
      "conv_count":         62,
      "conv_rate_pct":    "25.83"
    },
    {
      "source":           "(unknown)",
      "total_leads":         5,
      "dialed_count":        3,
      "contacted_count":     2,
      "conv_count":          0,
      "conv_rate_pct":     "0.00"
    }
  ]
}

GET /api/telesales/reports/time-series?campaign_id=43&group_by=day&date_from=...&date_to=...

Trả về mảng phẳng — không có wrapper {group_by, metrics, series}.

Query parameter bổ sung

FieldTypeRequiredMô tảGiá trị hợp lệ
group_bystringoptionalBước nhóm thời gianday (default) / week / hour

Response fields (mỗi item trong data[])

FieldTypeMô tảGiá trị hợp lệ
bucketstringMốc thời gian — format theo group_bydayYYYY-MM-DD; weekYYYY-Www (ISO 8601); hourYYYY-MM-DD HH:00:00
dialsintegerSố cuộc đã quay trong bucket≥ 0
answersintegerSố cuộc khách bắt máy≥ 0
talk_secintegerTổng thời gian đàm thoại (giây)≥ 0
conversionsintegerSố cuộc chốt thành công≥ 0
json
{
  "data": [
    { "bucket": "2026-06-01", "dials": 110, "answers": 68, "talk_sec":  9180, "conversions": 18 },
    { "bucket": "2026-06-02", "dials": 105, "answers": 71, "talk_sec": 10260, "conversions": 16 },
    { "bucket": "2026-06-05", "dials":  82, "answers": 55, "talk_sec":  6720, "conversions": 15 }
  ]
}

GET /api/telesales/reports/abandon-rate?campaign_id=43 (realtime)

Response của endpoint này phong phú hơn các báo cáo khác — chứa current (snapshot live) + breaches (lịch sử lần vượt ngưỡng gần đây).

Response fields

FieldTypeMô tảGiá trị hợp lệ
current.campaign_idintegerID chiến dịch
current.attempts_totalintegerTổng số attempt trong cửa sổ đo≥ 0
current.attempts_abandonedintegerSố attempt bị abandon trước khi agent kịp nói≥ 0
current.abandon_rate_pctnumberTỷ lệ abandon (%)0-100
current.window_minutesintegerĐộ dài cửa sổ đo (phút, default 30 ngày = 43.200)≥ 1
current.window_fromdatetimeMốc bắt đầu cửa sổISO 8601
current.window_todatetimeMốc kết thúc cửa sổISO 8601
current.campaign_namestringTên chiến dịch
current.campaign_statusstringTrạng thái chiến dịchdraft / active / paused / completed
current.limit_pctnumberNgưỡng PDPL/TCPA cho phépdefault 3
current.breachedboolĐang vượt ngưỡng hay không
breaches[]arrayLịch sử các snapshot đã vượt ngưỡng (rỗng nếu chưa từng vượt)
json
{
  "data": {
    "current": {
      "campaign_id":           43,
      "attempts_total":         1,
      "attempts_abandoned":     0,
      "abandon_rate_pct":       0,
      "window_minutes":     43200,
      "window_from":      "2026-05-10 02:31:14",
      "window_to":        "2026-06-09 02:31:14",
      "tenant_id":              1,
      "campaign_name":     "Outbound Sales Q3-2026 03",
      "campaign_status":   "active",
      "limit_pct":              3,
      "breached":           false
    },
    "breaches": []
  }
}

Khi breached=true, mảng breaches chứa lịch sử snapshot (các cửa sổ thời gian đã vượt giới hạn). Client dùng để render banner cảnh báo và vẽ trend.

9.2 Export CSV / Excel

http
GET /api/telesales/reports/{report}/export?format=csv|xlsx

{report} ∈ {dashboard, disposition-breakdown, agent-performance, funnel, caller-id-health, hour-dow-heatmap, lead-source-attribution, time-series}.

Response: file stream (Content-Type: text/csv hoặc application/vnd.openxmlformats-officedocument.spreadsheetml.sheet).

Layout export mặc định là chuẩn chung. Template Excel theo từng khách hàng (thứ tự cột, label header, conditional formatting riêng) được cấu hình trong gói cấu hình riêng.

Cấp phép theo điều khoản sử dụng của Zorio.