photum/backend/cmd/importer/main.go
NANDO9322 28b76a0f54 feat(fot-management): implementação de ações editar/excluir e correção no mapeamento da agenda
- Implementadas ações de Editar e Excluir na página de Gestão de FOT
- Adicionado filtro de busca para FOTs
- Corrigido desalinhamento de colunas na tabela de Gestão de FOT
- Atualizado FotForm para suportar a edição de registros existentes
- Corrigido erro de renderização do React no Dashboard mapeando corretamente os objetos de atribuição
- Removidos dados de mock (INITIAL_EVENTS) e corrigido erro de referência nula no DataContext
- Adicionados métodos de atualização/exclusão ao apiService
2025-12-16 18:10:46 -03:00

231 lines
6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"context"
"database/sql"
"encoding/csv"
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/joho/godotenv"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/transform"
)
func main() {
// Load .env
// Try loading from current directory first, typical when running 'go run cmd/importer/main.go' from root
if err := godotenv.Load(".env"); err != nil {
// Fallback for when running from cmd/importer
if err := godotenv.Load("../../.env"); err != nil {
log.Println("Warning: .env file not found in .env or ../../.env")
}
}
dbURL := os.Getenv("DB_DSN")
if dbURL == "" {
log.Fatal("DB_DSN is not set")
}
db, err := sql.Open("pgx", dbURL)
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
defer db.Close()
if err := db.Ping(); err != nil {
log.Fatalf("Failed to ping database: %v", err)
}
// Open CSV File
filename := "importacao_fots.csv"
f, err := os.Open(filename)
if err != nil {
log.Fatalf("Failed to open CSV file: %v", err)
}
defer f.Close()
// Use Windows-1252 Decoder
r := csv.NewReader(transform.NewReader(f, charmap.Windows1252.NewDecoder()))
r.Comma = ';'
r.LazyQuotes = true // Allow messy quotes
// Read Header
header, err := r.Read()
if err != nil {
log.Fatalf("Failed to read header: %v", err)
}
fmt.Printf("Header: %v\n", header)
ctx := context.Background()
rowsProcessed := 0
rowsInserted := 0
rowsFailed := 0
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Printf("Error reading row %d: %v. Skipping.", rowsProcessed+1, err)
rowsFailed++
continue
}
rowsProcessed++
// Map Columns (Indices based on "FOT;Empresa;EF I / EF II;Observa‡äes;Institui‡Æo;Ano Formatura;Cidade;Estado;Gastos Capta‡Æo;Pr Venda")
// 0: FOT
// 1: Empresa
// 2: Cursos (was EF I / EF II)
// 3: Observacoes
// 4: Instituicao
// 5: Ano Formatura
// 6: Cidade
// 7: Estado
// 8: Gastos Captacao
// 9: Pre Venda
fotStr := strings.TrimSpace(record[0])
empresaName := strings.TrimSpace(record[1])
cursoName := strings.TrimSpace(record[2])
observacoes := strings.TrimSpace(record[3])
instituicao := strings.TrimSpace(record[4])
anoFormatura := strings.TrimSpace(record[5])
cidade := strings.TrimSpace(record[6])
estado := strings.TrimSpace(record[7])
gastosStr := strings.TrimSpace(record[8])
preVendaStr := strings.TrimSpace(record[9])
// Basic Validation
if fotStr == "" || fotStr == "FOT" { // Skip header repetition or empty lines
continue
}
fot, err := strconv.Atoi(fotStr)
if err != nil {
log.Printf("Row %d: Invalid FOT '%s'. Skipping.", rowsProcessed, fotStr)
rowsFailed++
continue
}
// 1. Upsert Empresa
var empresaID string
if empresaName == "" {
empresaName = "Não Identificada"
}
err = db.QueryRowContext(ctx, `
INSERT INTO empresas (nome) VALUES ($1)
ON CONFLICT (nome) DO UPDATE SET nome = EXCLUDED.nome
RETURNING id`, empresaName).Scan(&empresaID)
if err != nil {
log.Printf("Row %d: Failed to upsert empresa '%s': %v", rowsProcessed, empresaName, err)
rowsFailed++
continue
}
// 2. Upsert Curso
var cursoID string
if cursoName == "" || cursoName == "-" {
cursoName = "Geral"
}
err = db.QueryRowContext(ctx, `
INSERT INTO cursos (nome) VALUES ($1)
ON CONFLICT (nome) DO UPDATE SET nome = EXCLUDED.nome
RETURNING id`, cursoName).Scan(&cursoID)
if err != nil {
log.Printf("Row %d: Failed to upsert curso '%s': %v", rowsProcessed, cursoName, err)
rowsFailed++
continue
}
// 3. Upsert Ano Formatura
var anoID string
if anoFormatura == "" {
anoFormatura = "Indefinido"
}
err = db.QueryRowContext(ctx, `
INSERT INTO anos_formaturas (ano_semestre) VALUES ($1)
ON CONFLICT (ano_semestre) DO UPDATE SET ano_semestre = EXCLUDED.ano_semestre
RETURNING id`, anoFormatura).Scan(&anoID)
if err != nil {
log.Printf("Row %d: Failed to upsert ano '%s': %v", rowsProcessed, anoFormatura, err)
rowsFailed++
continue
}
// 4. Parse Currency (Gastos Captação)
// Format: "R$ 2.176,60" -> 2176.60
gastosVal := 0.0
if gastosStr != "" && gastosStr != "-" {
// Remove "R$", "." and trim
clean := strings.ReplaceAll(gastosStr, "R$", "")
clean = strings.ReplaceAll(clean, ".", "") // Remove thousand separator
clean = strings.ReplaceAll(clean, ",", ".") // Replace decimal separator
clean = strings.TrimSpace(clean)
// Handle trailing/leading spaces hidden chars if any
// Just parse float
val, err := strconv.ParseFloat(clean, 64)
if err == nil {
gastosVal = val
} else {
// log.Printf("Row %d: Warning parsing gastos '%s' -> '%s': %v", rowsProcessed, gastosStr, clean, err)
}
}
// 5. Parse Boolean (Pre Venda)
preVenda := false
if strings.ToLower(preVendaStr) == "sim" {
preVenda = true
}
// 6. Insert Cadastro FOT
_, err = db.ExecContext(ctx, `
INSERT INTO cadastro_fot (
fot, empresa_id, curso_id, ano_formatura_id,
instituicao, cidade, estado, observacoes,
gastos_captacao, pre_venda
) VALUES (
$1, $2, $3, $4,
$5, $6, $7, $8,
$9, $10
)
ON CONFLICT (fot) DO UPDATE SET
empresa_id = EXCLUDED.empresa_id,
curso_id = EXCLUDED.curso_id,
ano_formatura_id = EXCLUDED.ano_formatura_id,
instituicao = EXCLUDED.instituicao,
cidade = EXCLUDED.cidade,
estado = EXCLUDED.estado,
observacoes = EXCLUDED.observacoes,
gastos_captacao = EXCLUDED.gastos_captacao,
pre_venda = EXCLUDED.pre_venda,
updated_at = NOW()
`,
fot, empresaID, cursoID, anoID,
instituicao, cidade, estado, observacoes,
gastosVal, preVenda,
)
if err != nil {
log.Printf("Row %d: Failed to insert FOT %d: %v", rowsProcessed, fot, err)
rowsFailed++
} else {
rowsInserted++
if rowsInserted%50 == 0 {
fmt.Printf("Progress: %d records upserted...\n", rowsInserted)
}
}
}
fmt.Printf("\n--- Import Summary ---\n")
fmt.Printf("Total Rows Processed: %d\n", rowsProcessed)
fmt.Printf("Successfully Upserted: %d\n", rowsInserted)
fmt.Printf("Failed: %d\n", rowsFailed)
}