package logic import ( "context" "errors" "spark-server/internal/module/energy/entity" "spark-server/internal/pkg/errs" "spark-server/internal/pkg/reqctx" "spark-server/internal/pkg/validate" ) // MakeupQuery is eligibility for a past day. type MakeupQuery struct { CanReSign bool `json:"can_resign"` NeedWatchVideoCount int `json:"need_watch_video_count"` Date int `json:"date"` } // MakeupInput performs makeup for a past day. type MakeupInput struct { Date int `json:"date" validate:"required,gt=19700101" label:"field.date" errmsg:"required:validate.required;gt:validate.required"` } // MakeupCheck returns whether the user may makeup the given YYYYMMDD day. func (s *Service) MakeupCheck(ctx context.Context, userID int64, date int) (*MakeupQuery, error) { if !s.ready() || userID <= 0 { return nil, errs.ErrUnauthorized } out := &MakeupQuery{Date: date, NeedWatchVideoCount: 0} ok, err := s.canMakeup(ctx, userID, date) if err != nil { return nil, err } out.CanReSign = ok return out, nil } // Makeup credits a missed past day (no rewarded-video gate in v1). func (s *Service) Makeup(ctx context.Context, userID int64, in *MakeupInput) (*CheckInResult, error) { if !s.ready() || userID <= 0 { return nil, errs.ErrUnauthorized } if in == nil { return nil, errs.ErrInvalidArgument } if err := validate.StructLang(reqctx.Lang(ctx), in); err != nil { return nil, err } ok, err := s.canMakeup(ctx, userID, in.Date) if err != nil { return nil, err } if !ok { return nil, errs.ErrForbidden } return s.signDay(ctx, userID, in.Date, entity.KindMakeup, "补签奖励") } func (s *Service) canMakeup(ctx context.Context, userID int64, date int) (bool, error) { if _, ok := parseDayKey(date); !ok { return false, errs.ErrInvalidArgument } today := dayKeyOf(s.now()) if date >= today { return false, nil } // Only allow makeup within the current calendar month. ty, tm := today/10000, (today/100)%100 dy, dm := date/10000, (date/100)%100 if ty != dy || tm != dm { return false, nil } if _, err := s.repo.GetSign(ctx, userID, date); err == nil { return false, nil } else if err != nil && !errors.Is(err, errs.ErrNotFound) { return false, err } return true, nil }