// package order -- сущность заказа бронирвоания package order import ( "encoding/json" "fmt" "strings" "time" "adt/pkg/alias" ) // Order -- сущность заказа бронирования type Order struct { Id_ alias.OrderId `json:"id"` // Номер заказа HotelId_ alias.HotelId `json:"hotel_id"` // ID отеля RoomID_ alias.RoomId `json:"room_id"` // ID номера в указанном отеле UserEmail_ alias.Email `json:"email"` // Email пользователя From_ time.Time `json:"from"` // Дата заезда To_ time.Time `json:"to"` // Дата выезда включительно LstDay_ []alias.Date `json:"lst_day"` // Список дней бронирования } // Unmarshall -- десерилаизует структуру Order из json func Unmarshall(binData []byte) (*Order, error) { sf := &Order{} err := json.Unmarshal(binData, sf) if err != nil { return nil, fmt.Errorf("order.Unmarshall(): in json.Unmarshal, err=\n\t%w", err) } if sf.HotelId_ == "" { return nil, fmt.Errorf("order.Unmarshall(): hotel_id is empty") } if sf.RoomID_ == "" { return nil, fmt.Errorf("order.Unmarshall(): room_id is empty") } if sf.UserEmail_ == "" { return nil, fmt.Errorf("order.Unmarshall(): email is empty") } if sf.From_ == (time.Time{}) { return nil, fmt.Errorf("order.Unmarshall(): from is empty") } { // Проверка email if !strings.Contains(string(sf.UserEmail_), "@") { return nil, fmt.Errorf("order.Unmarshall(): email(%q) not have @", sf.UserEmail_) } if !strings.Contains(string(sf.UserEmail_), ".") { return nil, fmt.Errorf("order.Unmarshall(): email(%q) not have .", sf.UserEmail_) } } if sf.To_ == (time.Time{}) { return nil, fmt.Errorf("order.Unmarshall(): to is empty") } if err := sf.daysBetween(); err != nil { return nil, fmt.Errorf("order.Unmarshall(): in calc daysBetween, err=\n\t%w", err) } sf.Id_ = alias.OrderId(fmt.Sprintf("%v.%v.%v.%v", sf.HotelId_, sf.RoomID_, sf.From(), sf.To())) return sf, nil } // Marshall -- сериализует структуру Order func (sf *Order) Marshall() []byte { binData, _ := json.Marshal(sf) return binData } // Room -- возвращает ID номера в отеле func (sf *Order) Room() alias.RoomId { return sf.RoomID_ } // Hotel -- возвращает ID отеля func (sf *Order) Hotel() alias.HotelId { return sf.HotelId_ } // Id -- возвращает номер заказа func (sf *Order) Id() alias.OrderId { return sf.Id_ } func (sf *Order) daysBetween() error { if sf.From_.After(sf.To_) { return fmt.Errorf("Order.daysBetween(): from > to") } sf.LstDay_ = make([]alias.Date, 0) cleanTo := cleanDay(sf.To_) cleanNext := cleanDay(sf.From_) for { // Перебор дней на добавление cleanFrom := cleanDay(cleanNext) if cleanFrom.After(cleanTo) { break } dateOrder := alias.Date(cleanNext.UTC().Format("2006-01-02")) sf.LstDay_ = append(sf.LstDay_, dateOrder) if len(sf.LstDay_) > 60 { return fmt.Errorf("Order.daysBetween(): lst_day > 60") } cleanNext = cleanNext.AddDate(0, 0, 1) } if len(sf.LstDay_) == 0 { return fmt.Errorf("Order.daysBetween(): lst_day is empty") } return nil } // Округялет дату до дня, FIXME: дата заезда и выезда в 12:00 func cleanDay(timestamp time.Time) time.Time { return time.Date(timestamp.Year(), timestamp.Month(), timestamp.Day(), 0, 0, 0, 0, time.UTC) } // listDay -- возвращает список дней бронирования func (sf *Order) ListDay() []alias.Date { return sf.LstDay_ } // To -- возвращает дату окончания бронирования (включительно) func (sf *Order) To() alias.Date { return alias.Date(sf.To_.UTC().Format("2006-01-02")) } // From -- возвращает дату начала бронирования func (sf *Order) From() alias.Date { return alias.Date(sf.From_.UTC().Format("2006-01-02")) }