dana-medical-site/internal/api/pbx_test.go
2026-10-14 13:33:13 +00:00

113 lines
5.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
}