113 lines
5.8 KiB
Go
113 lines
5.8 KiB
Go
package api
|
||
|
||
import (
|
||
"context"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"dana/internal/storage"
|
||
)
|
||
|
||
func pbxCall(uid, typ, status, client, via, channel string, min, wait, dur int) storage.PBXCallRow {
|
||
base := time.Date(2026, 9, 23, 8, 0, 0, 0, time.UTC)
|
||
return storage.PBXCallRow{UID: uid, Type: typ, Status: status, Client: client, ClientKey: phoneKey(client),
|
||
Via: via, ViaKey: phoneKey(via), Channel: channel, UserName: "КЦ DANA общий",
|
||
StartedAt: base.Add(time.Duration(min) * time.Minute), Wait: wait, Duration: dur}
|
||
}
|
||
|
||
func TestBuildPBXReport(t *testing.T) {
|
||
calls := []storage.PBXCallRow{
|
||
pbxCall("1", "in", "success", "79281112233", "79285440094", "2гис", 0, 5, 60),
|
||
pbxCall("2", "missed", "missed", "79284445566", "79285088306", "яндекс", 1, 20, 0),
|
||
pbxCall("3", "missed", "missed", "79284445566", "79285088306", "яндекс", 2, 15, 0),
|
||
pbxCall("4", "missed", "missed", "79287770000", "79285088306", "яндекс", 3, 10, 0),
|
||
pbxCall("5", "out", "success", "79287770000", "79280470055", "все номера", 10, 0, 40), // перезвонили
|
||
pbxCall("6", "in", "success", "79289990000", "79280468877", "", 11, 3, 30), // линия без канала — не в отчёте
|
||
pbxCall("7", "missed", "missed", "79283330000", "79285088306", "яндекс", 12, 10, 0),
|
||
pbxCall("8", "out", "success", "79283330000", "79285010458", "", 13, 0, 25), // перезвонили с линии без канала
|
||
pbxCall("9", "out", "success", "79286660000", "79285010458", "", 14, 0, 25), // исходящий линии без канала
|
||
}
|
||
rep := buildPBXReport(calls)
|
||
if rep.Total.Incoming != 5 || rep.Total.Answered != 1 || rep.Total.Missed != 4 || rep.Total.Clients != 4 || rep.Outgoing != 1 {
|
||
t.Fatalf("итого: %+v, исходящих %d", rep.Total, rep.Outgoing)
|
||
}
|
||
// потерян только 79284445566: остальным перезвонили, в том числе с линии без канала
|
||
if len(rep.Lost) != 1 || rep.Lost[0].Client != "79284445566" || rep.Lost[0].Attempts != 2 || rep.Lost[0].Channel != "Яндекс" {
|
||
t.Fatalf("потерянные: %+v", rep.Lost)
|
||
}
|
||
if len(rep.Channels) != 3 || rep.Channels[2].Channel != "Основной номер" || rep.Channels[2].Outgoing != 1 {
|
||
t.Fatalf("каналы: %+v", rep.Channels)
|
||
}
|
||
if rep.Total.Outgoing != 1 || rep.Total.OutTalk != 40 {
|
||
t.Fatalf("исходящие по линиям: %+v", rep.Total)
|
||
}
|
||
from := time.Date(2026, 9, 23, 0, 0, 0, 0, time.UTC)
|
||
sr := buildPBXSeries(&rep, calls, from, from.AddDate(0, 0, 1))
|
||
sum := func(v []float64) (s float64) {
|
||
for _, x := range v {
|
||
s += x
|
||
}
|
||
return
|
||
}
|
||
if sr.Step != "hour" || len(sr.Labels) != 24 || sum(sr.All) != 6 || sum(sr.Incoming) != 5 || sum(sr.Outgoing) != 1 ||
|
||
sum(sr.Missed) != 4 || sum(sr.Lost) != 1 || sr.Incoming[8] != 5 {
|
||
t.Fatalf("ряды: %+v", sr)
|
||
}
|
||
if d := buildPBXSeries(&rep, calls, from.AddDate(0, 0, -9), from.AddDate(0, 0, 1)); d.Step != "day" || len(d.All) != 10 || d.All[9] != 6 {
|
||
t.Fatalf("ряды по дням: %+v", d)
|
||
}
|
||
ya := rep.Channels[0]
|
||
if ya.Channel != "Яндекс" || ya.Incoming != 4 || ya.Clients != 3 || ya.Missed != 4 || ya.MissedLost != 1 || ya.AnsweredRate != 0 {
|
||
t.Fatalf("яндекс: %+v", ya)
|
||
}
|
||
}
|
||
|
||
func TestPBXListsInChannelsReport(t *testing.T) {
|
||
calls := []storage.PBXCallRow{
|
||
pbxCall("1", "in", "success", "89281112233", "79285440094", "2гис", 0, 5, 60),
|
||
pbxCall("2", "missed", "missed", "79284445566", "79285088306", "яндекс", 1, 20, 0),
|
||
pbxCall("3", "out", "success", "79287770000", "79280470055", "все номера", 2, 0, 40),
|
||
pbxCall("4", "in", "success", "79289990000", "79280468877", "", 3, 3, 30), // линия без канала — не в отчёте
|
||
pbxCall("5", "in", "success", "79281230000", "79280470055", "все номера", 4, 3, 30),
|
||
}
|
||
lists, unmapped := pbxChannelNumbers(calls)
|
||
if len(lists["все номера"]) != 3 || len(lists["2гис"]) != 1 || len(lists["яндекс"]) != 1 || len(unmapped) != 1 || len(lists) != 3 {
|
||
t.Fatalf("списки: %v, без канала: %v", lists, unmapped)
|
||
}
|
||
// книга только с выгрузкой 1С — каналы целиком из АТС
|
||
book := xlsxBook(t, map[string][][]string{
|
||
"Лист_1": {{"Пациент", "Мобильный телефон", "Количество", "СуммаИтого"},
|
||
{"Иванова Анна", "79281112233", "1", "1500"}, {"Петров Олег", "79284445566", "1", "2000"}, {"Итого", "", "2", "3500"}},
|
||
}, []string{"Лист_1"})
|
||
o := matchOpts{pbxLists: lists, pbxInfo: &pbxSourceInfo{From: "2026-09-23", To: "2026-09-23", Calls: 4, Unmapped: unmapped}}
|
||
res, sumAny, err := (&API{}).phoneMatchOpts(context.Background(), &progressTracker{}, "1c.xlsx", book, o)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
s := sumAny.(channelsSummary)
|
||
if g := channelByName(s, "2Гис"); g.Leads != 1 || g.Patients != 1 || g.Revenue != 1500 {
|
||
t.Errorf("2ГИС: %+v", g)
|
||
}
|
||
if y := channelByName(s, "Яндекс"); y.Leads != 1 || y.Patients != 1 || y.Revenue != 2000 {
|
||
t.Errorf("Яндекс: %+v", y)
|
||
}
|
||
if c := channelByName(s, "Колл-центр (все номера)"); c.Leads != 3 || c.Patients != 2 {
|
||
t.Errorf("колл-центр: %+v", c)
|
||
}
|
||
if s.PBX == nil || s.PBX.Calls != 4 {
|
||
t.Errorf("нет сведений об АТС в итогах")
|
||
}
|
||
if want := "Номера каналов из АТС МегаФон"; !strings.Contains(string(res), want) {
|
||
t.Errorf("в CSV нет строки %q", want)
|
||
}
|
||
}
|
||
|
||
func TestMergePBXListsSameChannel(t *testing.T) {
|
||
sheets := []Sheet{{Name: "Инстаграмм", Rows: [][]string{{"79281112233"}}}}
|
||
out := mergePBXLists(sheets, map[string][]string{"инстаграм": {"79284445566"}, "яндекс": {"79287770000"}})
|
||
if len(out) != 2 || len(out[0].Rows) != 2 || out[1].Name != "яндекс" {
|
||
t.Fatalf("листы: %+v", out)
|
||
}
|
||
}
|