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

80 lines
3.9 KiB
Go
Raw 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 storage
import "context"
// DoctorQuality — то, чего нет в списке врачей админки: записи биографии по видам,
// отзывы и заявки по каждому врачу. Полноту карточки считает страница «Дашборд врачей».
type DoctorQuality struct {
ID int64 `json:"id"`
Education int `json:"education"`
Experience int `json:"experience"`
Training int `json:"training"`
Awards int `json:"awards"`
Conferences int `json:"conferences"`
ReviewsPending int `json:"reviews_pending"`
ReviewsLive int `json:"reviews_published"`
RatingSum int `json:"rating_sum"` // сумма оценок всех отзывов с оценкой
RatingCount int `json:"rating_count"` // сколько отзывов с оценкой
Leads int `json:"leads"` // заявки к врачу или со страницы врача, без спама
KidsFrom bool `json:"kids_from"`
Languages bool `json:"languages"`
PrimarySpecialty *string `json:"primary_specialty"`
}
type DoctorQualityReport struct {
Doctors []DoctorQuality `json:"doctors"`
ReviewsPendingTotal int `json:"reviews_pending_total"`
ReviewsPendingNoDoc int `json:"reviews_pending_clinic"` // отзывы о клинике в целом
ReviewsLiveTotal int `json:"reviews_published_total"`
LeadsTotal int `json:"leads_total"`
}
func (s *Storage) DoctorQuality(ctx context.Context) (*DoctorQualityReport, error) {
rep := &DoctorQualityReport{Doctors: []DoctorQuality{}}
rows, err := s.pool.Query(ctx, `
SELECT d.id,
count(*) FILTER (WHERE e.kind = 'education'),
count(*) FILTER (WHERE e.kind = 'experience'),
count(*) FILTER (WHERE e.kind = 'training'),
count(*) FILTER (WHERE e.kind = 'award'),
count(*) FILTER (WHERE e.kind = 'conference'),
(SELECT count(*) FROM reviews r WHERE r.doctor_id = d.id AND r.status = 'pending'),
(SELECT count(*) FROM reviews r WHERE r.doctor_id = d.id AND r.status = 'published'),
(SELECT COALESCE(sum(r.rating), 0) FROM reviews r WHERE r.doctor_id = d.id AND r.rating IS NOT NULL AND r.status <> 'rejected'),
(SELECT count(r.rating) FROM reviews r WHERE r.doctor_id = d.id AND r.status <> 'rejected'),
(SELECT count(*) FROM leads l WHERE l.status <> 'spam' AND (l.doctor_id = d.id OR
(l.doctor_id IS NULL AND l.page_url LIKE '%/company/staff/%/' || d.slug || '/%'))),
d.accepts_kids_from IS NOT NULL,
cardinality(d.languages) > 0,
(SELECT sp.name_plural FROM doctor_specialties ds JOIN specialties sp ON sp.id = ds.specialty_id
WHERE ds.doctor_id = d.id ORDER BY ds.is_primary DESC, sp.sort, sp.id LIMIT 1)
FROM doctors d
LEFT JOIN doctor_bio_entries e ON e.doctor_id = d.id
WHERE d.deleted_at IS NULL
GROUP BY d.id
ORDER BY d.id`)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var q DoctorQuality
if err := rows.Scan(&q.ID, &q.Education, &q.Experience, &q.Training, &q.Awards, &q.Conferences,
&q.ReviewsPending, &q.ReviewsLive, &q.RatingSum, &q.RatingCount, &q.Leads,
&q.KidsFrom, &q.Languages, &q.PrimarySpecialty); err != nil {
return nil, err
}
rep.Doctors = append(rep.Doctors, q)
}
if err := rows.Err(); err != nil {
return nil, err
}
err = s.pool.QueryRow(ctx, `
SELECT count(*) FILTER (WHERE status = 'pending'),
count(*) FILTER (WHERE status = 'pending' AND doctor_id IS NULL),
count(*) FILTER (WHERE status = 'published'),
(SELECT count(*) FROM leads WHERE status <> 'spam')
FROM reviews`).Scan(&rep.ReviewsPendingTotal, &rep.ReviewsPendingNoDoc, &rep.ReviewsLiveTotal, &rep.LeadsTotal)
return rep, err
}