107 lines
4.9 KiB
Go
107 lines
4.9 KiB
Go
package api
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"dana/internal/bitrix"
|
||
"dana/internal/storage"
|
||
)
|
||
|
||
func TestConfirmDeadline(t *testing.T) {
|
||
cfg := storage.DefaultBookingSettings // 24 ч после записи или 2 ч до приёма
|
||
created := time.Date(2026, 10, 9, 22, 0, 0, 0, moscow)
|
||
cases := []struct {
|
||
name string
|
||
start time.Time
|
||
want time.Time
|
||
}{
|
||
{"приём через три дня — 24 ч после записи", created.Add(72 * time.Hour), created.Add(24 * time.Hour)},
|
||
{"приём завтра утром — за 2 ч до приёма", created.Add(12 * time.Hour), created.Add(10 * time.Hour)},
|
||
{"приём через час — не раньше 30 минут после записи", created.Add(time.Hour), created.Add(30 * time.Minute)},
|
||
}
|
||
for _, c := range cases {
|
||
got, ok := confirmDeadline(created, c.start, cfg)
|
||
if !ok || !got.Equal(c.want) {
|
||
t.Errorf("%s: срок %v, ждали %v", c.name, got, c.want)
|
||
}
|
||
}
|
||
if _, ok := confirmDeadline(created, created.Add(72*time.Hour), storage.BookingSettings{}); ok {
|
||
t.Error("оба правила выключены — автоотмены быть не должно")
|
||
}
|
||
}
|
||
|
||
func TestDecideConfirm(t *testing.T) {
|
||
cfg := storage.DefaultBookingSettings
|
||
created := time.Date(2026, 10, 9, 10, 0, 0, 0, moscow)
|
||
start := created.Add(48 * time.Hour)
|
||
soon := created.Add(time.Hour)
|
||
late := created.Add(25 * time.Hour) // срок (24 ч) прошёл, приём ещё впереди
|
||
cases := []struct {
|
||
name string
|
||
semantic string
|
||
now time.Time
|
||
want confirmAction
|
||
}{
|
||
{"оператор подтвердил", bitrix.SemanticSuccess, soon, confirmOK},
|
||
{"оператор отменил", bitrix.SemanticFailure, soon, confirmCancel},
|
||
{"в работе, срок не вышел", bitrix.SemanticProcess, soon, confirmWait},
|
||
{"лид удалён, срок не вышел", "", soon, confirmWait},
|
||
{"в работе, срок вышел", bitrix.SemanticProcess, late, confirmExpire},
|
||
{"подтвердили даже после срока — подтверждаем", bitrix.SemanticSuccess, late, confirmOK},
|
||
{"провал после начала приёма — в 1С не трогаем", bitrix.SemanticFailure, start.Add(time.Minute), confirmMissed},
|
||
{"никто не ответил до приёма — в 1С не трогаем", bitrix.SemanticProcess, start, confirmMissed},
|
||
}
|
||
for _, c := range cases {
|
||
if got := decideConfirm(c.semantic, created, start, c.now, cfg); got != c.want {
|
||
t.Errorf("%s: %v, ждали %v", c.name, got, c.want)
|
||
}
|
||
}
|
||
if got := decideConfirm(bitrix.SemanticProcess, created, start, late, storage.BookingSettings{}); got != confirmWait {
|
||
t.Errorf("автоотмена выключена: %v, ждали ожидание", got)
|
||
}
|
||
}
|
||
|
||
func TestLeadOnlyDraftAsksToBookManually(t *testing.T) {
|
||
it := storage.ConfirmItem{
|
||
Start: time.Date(2026, 10, 12, 15, 30, 0, 0, moscow), Patient: "Анна", Phone: "+7 928 000 00 00",
|
||
DoctorName: "Петрова <script>", OnecID: "",
|
||
}
|
||
d := leadOnlyDraft(it)
|
||
if !strings.HasPrefix(d.Title, "Заявка на запись: ") || d.SourceID != bitrixSiteSourceID || d.Phone != "+79280000000" {
|
||
t.Errorf("заголовок/источник/телефон: %+v", d)
|
||
}
|
||
for _, want := range []string{"НЕ закреплено", "запишите его в 1С вручную", "12.10.2026 в 15:30", "<script>"} {
|
||
if !strings.Contains(d.Comments, want) {
|
||
t.Errorf("в комментарии нет %q: %q", want, d.Comments)
|
||
}
|
||
}
|
||
if strings.Contains(d.Comments, "<script>") || strings.Contains(d.Comments, "№ записи в 1С") {
|
||
t.Errorf("лишнее в комментарии: %q", d.Comments)
|
||
}
|
||
}
|
||
|
||
func TestLeadDraftEscapesPatientInput(t *testing.T) {
|
||
it := storage.ConfirmItem{
|
||
Start: time.Date(2026, 10, 12, 15, 30, 0, 0, moscow), CreatedAt: time.Date(2026, 10, 9, 10, 0, 0, 0, moscow),
|
||
Patient: "Анна", Phone: "8 (928) 000-00-00", DoctorName: "Иванов <b>И.</b>", Branch: "ул. Ленина, 1",
|
||
ServiceName: "Консультация", OnecID: "A-17",
|
||
}
|
||
d := leadDraft(it, storage.DefaultBookingSettings)
|
||
if d.Phone != "+79280000000" {
|
||
t.Errorf("телефон не нормализован: %q", d.Phone)
|
||
}
|
||
if strings.Contains(d.Comments, "<b>") || !strings.Contains(d.Comments, "<b>") {
|
||
t.Errorf("HTML пациента/врача не экранирован: %q", d.Comments)
|
||
}
|
||
for _, want := range []string{"12.10.2026 в 15:30", "A-17", "Консультация", "Клиент записался", "отменится автоматически 10.10 в 10:00"} {
|
||
if !strings.Contains(d.Comments, want) {
|
||
t.Errorf("в комментарии нет %q: %q", want, d.Comments)
|
||
}
|
||
}
|
||
if d.SourceID != bitrixSiteSourceID || !strings.HasPrefix(d.Title, "Онлайн-запись: ") {
|
||
t.Errorf("источник/заголовок: %+v", d)
|
||
}
|
||
}
|