package model import "time" // WorkingHour represents a single day's working hours configuration for an inbox. // Reference: Chatwoot app/models/working_hour.rb // // Each inbox has 7 WorkingHour records (day_of_week 0-6), one per day. // Default: weekdays 9:00-17:00, weekends closed_all_day. // // Table: working_hours type WorkingHour struct { ID uint `gorm:"primaryKey" json:"id"` InboxID uint `gorm:"not null;index" json:"inbox_id"` AccountID uint `gorm:"index" json:"account_id"` DayOfWeek int `gorm:"not null" json:"day_of_week"` // 0=Sunday, 1=Monday, ..., 6=Saturday ClosedAllDay bool `gorm:"default:false" json:"closed_all_day"` // true → inbox closed entire day OpenAllDay bool `gorm:"default:false" json:"open_all_day"` // true → inbox open 24h OpenHour *int `gorm:"default:null" json:"open_hour"` // 0-23, nil when closed_all_day or open_all_day OpenMinutes *int `gorm:"default:null" json:"open_minutes"` // 0-59 CloseHour *int `gorm:"default:null" json:"close_hour"` // 0-23 CloseMinutes *int `gorm:"default:null" json:"close_minutes"` // 0-59 CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // TableName returns the GORM table name. func (WorkingHour) TableName() string { return "working_hours" } // Validate performs Chatwoot-equivalent validations: // - open_hour/close_hour must be 0-23 (unless closed_all_day) // - open_minutes/close_minutes must be 0-59 (unless closed_all_day) // - close time must be after open time (unless closed_all_day) // - open_all_day and closed_all_day cannot both be true func (wh *WorkingHour) Validate() map[string]string { errors := make(map[string]string) // Chatwoot: open_all_day_and_closed_all_day validation if wh.OpenAllDay && wh.ClosedAllDay { errors["open_all_day"] = "cannot be true when closed_all_day is also true" } if wh.ClosedAllDay { return errors // no further validation needed } // Chatwoot: inclusion validations (0-23 for hours, 0-59 for minutes) if wh.OpenHour != nil { if *wh.OpenHour < 0 || *wh.OpenHour > 23 { errors["open_hour"] = "must be between 0 and 23" } } else if !wh.OpenAllDay { errors["open_hour"] = "is required when not closed_all_day or open_all_day" } if wh.CloseHour != nil { if *wh.CloseHour < 0 || *wh.CloseHour > 23 { errors["close_hour"] = "must be between 0 and 23" } } else if !wh.OpenAllDay { errors["close_hour"] = "is required when not closed_all_day or open_all_day" } if wh.OpenMinutes != nil { if *wh.OpenMinutes < 0 || *wh.OpenMinutes > 59 { errors["open_minutes"] = "must be between 0 and 59" } } if wh.CloseMinutes != nil { if *wh.CloseMinutes < 0 || *wh.CloseMinutes > 59 { errors["close_minutes"] = "must be between 0 and 59" } } // Chatwoot: close_after_open validation // close time must be strictly after open time if wh.OpenHour != nil && wh.CloseHour != nil && wh.OpenMinutes != nil && wh.CloseMinutes != nil { openTotal := *wh.OpenHour * 60 + *wh.OpenMinutes closeTotal := *wh.CloseHour * 60 + *wh.CloseMinutes if closeTotal <= openTotal { errors["close_hour"] = "close time must be after open time" } } return errors } // EnsureOpenAllDayHours fills open/close fields when open_all_day is true. // Chatwoot: before_validation :ensure_open_all_day_hours // - When open_all_day: set open_hour=0, open_minutes=0, close_hour=23, close_minutes=59 func (wh *WorkingHour) EnsureOpenAllDayHours() { if wh.OpenAllDay { zero := 0 fiftyNine := 59 twentyThree := 23 wh.OpenHour = &zero wh.OpenMinutes = &zero wh.CloseHour = &twentyThree wh.CloseMinutes = &fiftyNine wh.ClosedAllDay = false } }