package cadastro_fot import ( "context" "errors" "strconv" "photum-backend/internal/db/generated" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) type Service struct { queries *generated.Queries } func NewService(queries *generated.Queries) *Service { return &Service{queries: queries} } type CreateInput struct { Fot string `json:"fot"` EmpresaID string `json:"empresa_id"` CursoID string `json:"curso_id"` AnoFormaturaID string `json:"ano_formatura_id"` Instituicao string `json:"instituicao"` Cidade string `json:"cidade"` Estado string `json:"estado"` Observacoes string `json:"observacoes"` GastosCaptacao float64 `json:"gastos_captacao"` PreVenda bool `json:"pre_venda"` } func (s *Service) Create(ctx context.Context, input CreateInput) (*generated.CadastroFot, error) { empresaUUID, _ := uuid.Parse(input.EmpresaID) cursoUUID, _ := uuid.Parse(input.CursoID) anoUUID, _ := uuid.Parse(input.AnoFormaturaID) res, err := s.queries.CreateCadastroFot(ctx, generated.CreateCadastroFotParams{ Fot: input.Fot, EmpresaID: pgtype.UUID{Bytes: empresaUUID, Valid: true}, CursoID: pgtype.UUID{Bytes: cursoUUID, Valid: true}, AnoFormaturaID: pgtype.UUID{Bytes: anoUUID, Valid: true}, Instituicao: pgtype.Text{String: input.Instituicao, Valid: true}, Cidade: pgtype.Text{String: input.Cidade, Valid: true}, Estado: pgtype.Text{String: input.Estado, Valid: true}, Observacoes: pgtype.Text{String: input.Observacoes, Valid: true}, GastosCaptacao: toPgNumeric(input.GastosCaptacao), PreVenda: pgtype.Bool{Bool: input.PreVenda, Valid: true}, }) if err != nil { return nil, err } return &res, nil } func (s *Service) List(ctx context.Context) ([]generated.ListCadastroFotRow, error) { return s.queries.ListCadastroFot(ctx) } func (s *Service) ListByEmpresa(ctx context.Context, empresaID string) ([]generated.ListCadastroFotByEmpresaRow, error) { uuidVal, err := uuid.Parse(empresaID) if err != nil { return nil, errors.New("invalid empresa_id") } // Note: ListCadastroFotByEmpresaRow is nearly identical to ListCadastroFotRow but we use the generated type return s.queries.ListCadastroFotByEmpresa(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true}) } func (s *Service) GetByID(ctx context.Context, id string) (*generated.GetCadastroFotByIDRow, error) { uuidVal, err := uuid.Parse(id) if err != nil { return nil, errors.New("invalid id") } item, err := s.queries.GetCadastroFotByID(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true}) return &item, err } func (s *Service) Update(ctx context.Context, id string, input CreateInput) (*generated.CadastroFot, error) { uuidVal, err := uuid.Parse(id) if err != nil { return nil, errors.New("invalid id") } empresaUUID, _ := uuid.Parse(input.EmpresaID) cursoUUID, _ := uuid.Parse(input.CursoID) anoUUID, _ := uuid.Parse(input.AnoFormaturaID) item, err := s.queries.UpdateCadastroFot(ctx, generated.UpdateCadastroFotParams{ ID: pgtype.UUID{Bytes: uuidVal, Valid: true}, Fot: input.Fot, EmpresaID: pgtype.UUID{Bytes: empresaUUID, Valid: true}, CursoID: pgtype.UUID{Bytes: cursoUUID, Valid: true}, AnoFormaturaID: pgtype.UUID{Bytes: anoUUID, Valid: true}, Instituicao: pgtype.Text{String: input.Instituicao, Valid: true}, Cidade: pgtype.Text{String: input.Cidade, Valid: true}, Estado: pgtype.Text{String: input.Estado, Valid: true}, Observacoes: pgtype.Text{String: input.Observacoes, Valid: true}, GastosCaptacao: toPgNumeric(input.GastosCaptacao), PreVenda: pgtype.Bool{Bool: input.PreVenda, Valid: true}, }) return &item, err } func (s *Service) Delete(ctx context.Context, id string) error { uuidVal, err := uuid.Parse(id) if err != nil { return errors.New("invalid id") } return s.queries.DeleteCadastroFot(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true}) } // Helper to convert float to numeric robustly func toPgNumeric(f float64) pgtype.Numeric { var n pgtype.Numeric s := strconv.FormatFloat(f, 'f', -1, 64) if err := n.Scan(s); err != nil { return pgtype.Numeric{Valid: false} } return n } // ImportInput for Batch Import type ImportInput struct { Fot string `json:"fot"` EmpresaNome string `json:"empresa_nome"` CursoNome string `json:"curso_nome"` AnoFormaturaLabel string `json:"ano_formatura_label"` Instituicao string `json:"instituicao"` Cidade string `json:"cidade"` Estado string `json:"estado"` Observacoes string `json:"observacoes"` GastosCaptacao float64 `json:"gastos_captacao"` PreVenda bool `json:"pre_venda"` } type ImportResult struct { SuccessCount int Errors []string } func (s *Service) BatchImport(ctx context.Context, items []ImportInput) ImportResult { result := ImportResult{Errors: []string{}} for i, item := range items { // 1. Resolve Empresa empresa, err := s.queries.GetEmpresaByNome(ctx, item.EmpresaNome) var empresaID pgtype.UUID if err != nil { // Create newEmp, errCreate := s.queries.CreateEmpresa(ctx, item.EmpresaNome) if errCreate != nil { result.Errors = append(result.Errors, "Row "+strconv.Itoa(i+1)+": Error creating empresa: "+errCreate.Error()) continue } empresaID = newEmp.ID } else { empresaID = empresa.ID } // 2. Resolve Curso curso, err := s.queries.GetCursoByNome(ctx, item.CursoNome) var cursoID pgtype.UUID if err != nil { newCurso, errCreate := s.queries.CreateCurso(ctx, item.CursoNome) if errCreate != nil { result.Errors = append(result.Errors, "Row "+strconv.Itoa(i+1)+": Error creating curso: "+errCreate.Error()) continue } cursoID = newCurso.ID } else { cursoID = curso.ID } // 3. Resolve Ano Formatura ano, err := s.queries.GetAnoFormaturaByNome(ctx, item.AnoFormaturaLabel) var anoID pgtype.UUID if err != nil { newAno, errCreate := s.queries.CreateAnoFormatura(ctx, item.AnoFormaturaLabel) if errCreate != nil { result.Errors = append(result.Errors, "Row "+strconv.Itoa(i+1)+": Error creating ano: "+errCreate.Error()) continue } anoID = newAno.ID } else { anoID = ano.ID } // 4. Insert Cadastro FOT // Check if exists? Or try create and catch duplicate // Ideally we update if exists? Let's just try Create for now. _, err = s.queries.CreateCadastroFot(ctx, generated.CreateCadastroFotParams{ Fot: item.Fot, EmpresaID: empresaID, CursoID: cursoID, AnoFormaturaID: anoID, Instituicao: pgtype.Text{String: item.Instituicao, Valid: true}, Cidade: pgtype.Text{String: item.Cidade, Valid: true}, Estado: pgtype.Text{String: item.Estado, Valid: true}, Observacoes: pgtype.Text{String: item.Observacoes, Valid: true}, GastosCaptacao: toPgNumeric(item.GastosCaptacao), PreVenda: pgtype.Bool{Bool: item.PreVenda, Valid: true}, }) if err != nil { result.Errors = append(result.Errors, "Row "+strconv.Itoa(i+1)+": Error inserting FOT "+item.Fot+": "+err.Error()) } else { result.SuccessCount++ } } return result }