38 lines
1.3 KiB
Go
38 lines
1.3 KiB
Go
package storage
|
|
|
|
import "context"
|
|
|
|
type BookingDay struct {
|
|
Date string `json:"date"`
|
|
DoctorIDs []int64 `json:"doctor_ids"`
|
|
}
|
|
|
|
// PublicBookingDays returns only dates and public doctor IDs, never patient data.
|
|
// Keep the occupancy rules identical to FreeOnecSlots, including cross-branch reservations.
|
|
func (s *Storage) PublicBookingDays(ctx context.Context) ([]BookingDay, error) {
|
|
rows, err := s.pool.Query(ctx, `
|
|
SELECT to_char(sl.start_at AT TIME ZONE 'Europe/Moscow','YYYY-MM-DD'),
|
|
array_agg(DISTINCT d.id ORDER BY d.id)
|
|
FROM onec_slots sl JOIN onec_doctors od ON od.onec_id=sl.doctor_onec_id
|
|
JOIN doctors d ON d.id=od.doctor_id
|
|
WHERE sl.status='free' AND sl.start_at>now() AND od.active
|
|
AND d.published AND d.deleted_at IS NULL AND NOT d.absent AND d.booking_provider='native'
|
|
AND NOT EXISTS(SELECT 1 FROM onec_appointments a
|
|
WHERE a.doctor_onec_id=sl.doctor_onec_id AND a.status IN('pending','booked','arrived')
|
|
AND a.start_at<sl.end_at AND COALESCE(a.end_at,a.start_at+interval '30 minutes')>sl.start_at)
|
|
GROUP BY 1 ORDER BY 1`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
out := []BookingDay{}
|
|
for rows.Next() {
|
|
var day BookingDay
|
|
if err := rows.Scan(&day.Date, &day.DoctorIDs); err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, day)
|
|
}
|
|
return out, rows.Err()
|
|
}
|