package codigos import ( "context" "time" "photum-backend/internal/db/generated" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) type Service struct { q *generated.Queries } func NewService(q *generated.Queries) *Service { return &Service{ q: q, } } type CreateCodigoInput struct { Codigo string `json:"codigo"` Descricao string `json:"descricao"` ValidadeDias int32 `json:"validade_dias"` EmpresaID string `json:"empresa_id"` Regiao string `json:"regiao"` // From context/header } func (s *Service) Create(ctx context.Context, input CreateCodigoInput) (generated.CodigosAcesso, error) { days := input.ValidadeDias var expiraEm time.Time if days == -1 { // Infinite: 100 years expiraEm = time.Now().AddDate(100, 0, 0) } else { if days <= 0 { days = 30 } expiraEm = time.Now().Add(time.Duration(days) * 24 * time.Hour) } var empresaUUID pgtype.UUID if input.EmpresaID != "" { parsed, err := uuid.Parse(input.EmpresaID) if err == nil { empresaUUID.Bytes = parsed empresaUUID.Valid = true } } // Default regiao to SP if empty regiao := input.Regiao if regiao == "" { regiao = "SP" } return s.q.CreateCodigoAcesso(ctx, generated.CreateCodigoAcessoParams{ Codigo: input.Codigo, Descricao: pgtype.Text{String: input.Descricao, Valid: input.Descricao != ""}, ValidadeDias: days, ExpiraEm: pgtype.Timestamptz{Time: expiraEm, Valid: true}, Ativo: true, EmpresaID: empresaUUID, Regiao: pgtype.Text{String: regiao, Valid: true}, }) } func (s *Service) List(ctx context.Context, regiao string) ([]generated.ListCodigosAcessoRow, error) { if regiao == "" { regiao = "SP" } return s.q.ListCodigosAcesso(ctx, pgtype.Text{String: regiao, Valid: true}) } func (s *Service) Delete(ctx context.Context, id string) error { uid, err := uuid.Parse(id) if err != nil { return err } // Convert uuid.UUID to pgtype.UUID var pgUUID pgtype.UUID pgUUID.Bytes = uid pgUUID.Valid = true return s.q.DeleteCodigoAcesso(ctx, pgUUID) } func (s *Service) GetByCode(ctx context.Context, code string) (generated.GetCodigoAcessoRow, error) { return s.q.GetCodigoAcesso(ctx, code) } func (s *Service) IncrementUse(ctx context.Context, id uuid.UUID) error { var pgUUID pgtype.UUID pgUUID.Bytes = id pgUUID.Valid = true return s.q.IncrementCodigoAcessoUso(ctx, pgUUID) } // Custom error for validation type AppError struct { Message string } func (e *AppError) Error() string { return e.Message } func (s *Service) Verify(ctx context.Context, code string) (*generated.GetCodigoAcessoRow, error) { c, err := s.q.GetCodigoAcesso(ctx, code) if err != nil { return nil, err // Not found or DB error } if !c.Ativo { return nil, &AppError{Message: "Código inativo"} } if time.Now().After(c.ExpiraEm.Time) { return nil, &AppError{Message: "Código expirado"} } return &c, nil }