Files
aggios.app/backend/internal/api/handlers/export.go

211 lines
5.0 KiB
Go

package handlers
import (
"aggios-app/backend/internal/api/middleware"
"aggios-app/backend/internal/domain"
"encoding/csv"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"github.com/xuri/excelize/v2"
)
// ExportLeads handles exporting leads in different formats
func (h *CRMHandler) ExportLeads(w http.ResponseWriter, r *http.Request) {
tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string)
if tenantID == "" {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "Missing tenant_id"})
return
}
format := r.URL.Query().Get("format")
if format == "" {
format = "csv"
}
customerID := r.URL.Query().Get("customer_id")
campaignID := r.URL.Query().Get("campaign_id")
var leads []domain.CRMLead
var err error
if campaignID != "" {
leads, err = h.repo.GetLeadsByListID(campaignID)
} else if customerID != "" {
leads, err = h.repo.GetLeadsByTenant(tenantID)
// Filter by customer manually
filtered := []domain.CRMLead{}
for _, lead := range leads {
if lead.CustomerID != nil && *lead.CustomerID == customerID {
filtered = append(filtered, lead)
}
}
leads = filtered
} else {
leads, err = h.repo.GetLeadsByTenant(tenantID)
}
if err != nil {
log.Printf("ExportLeads: Error fetching leads: %v", err)
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{"error": "Failed to fetch leads"})
return
}
switch strings.ToLower(format) {
case "json":
exportJSON(w, leads)
case "xlsx", "excel":
exportXLSX(w, leads)
default:
exportCSV(w, leads)
}
}
func exportJSON(w http.ResponseWriter, leads []domain.CRMLead) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Disposition", "attachment; filename=leads.json")
json.NewEncoder(w).Encode(map[string]interface{}{
"leads": leads,
"count": len(leads),
})
}
func exportCSV(w http.ResponseWriter, leads []domain.CRMLead) {
w.Header().Set("Content-Type", "text/csv")
w.Header().Set("Content-Disposition", "attachment; filename=leads.csv")
writer := csv.NewWriter(w)
defer writer.Flush()
// Header
header := []string{"ID", "Nome", "Email", "Telefone", "Status", "Origem", "Notas", "Tags", "Criado Em"}
writer.Write(header)
// Data
for _, lead := range leads {
tags := ""
if len(lead.Tags) > 0 {
tags = strings.Join(lead.Tags, ", ")
}
phone := ""
if lead.Phone != "" {
phone = lead.Phone
}
notes := ""
if lead.Notes != "" {
notes = lead.Notes
}
row := []string{
lead.ID,
lead.Name,
lead.Email,
phone,
lead.Status,
lead.Source,
notes,
tags,
lead.CreatedAt.Format("02/01/2006 15:04"),
}
writer.Write(row)
}
}
func exportXLSX(w http.ResponseWriter, leads []domain.CRMLead) {
f := excelize.NewFile()
defer f.Close()
sheetName := "Leads"
index, err := f.NewSheet(sheetName)
if err != nil {
log.Printf("Error creating sheet: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// Set active sheet
f.SetActiveSheet(index)
// Header style
headerStyle, _ := f.NewStyle(&excelize.Style{
Font: &excelize.Font{
Bold: true,
Size: 12,
},
Fill: excelize.Fill{
Type: "pattern",
Color: []string{"#4472C4"},
Pattern: 1,
},
Alignment: &excelize.Alignment{
Horizontal: "center",
Vertical: "center",
},
})
// Headers
headers := []string{"ID", "Nome", "Email", "Telefone", "Status", "Origem", "Notas", "Tags", "Criado Em"}
for i, header := range headers {
cell := fmt.Sprintf("%s1", string(rune('A'+i)))
f.SetCellValue(sheetName, cell, header)
f.SetCellStyle(sheetName, cell, cell, headerStyle)
}
// Data
for i, lead := range leads {
row := i + 2
tags := ""
if len(lead.Tags) > 0 {
tags = strings.Join(lead.Tags, ", ")
}
phone := ""
if lead.Phone != "" {
phone = lead.Phone
}
notes := ""
if lead.Notes != "" {
notes = lead.Notes
}
f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), lead.ID)
f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), lead.Name)
f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), lead.Email)
f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), phone)
f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), lead.Status)
f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), lead.Source)
f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), notes)
f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), tags)
f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), lead.CreatedAt.Format("02/01/2006 15:04"))
}
// Auto-adjust column widths
for i := 0; i < len(headers); i++ {
col := string(rune('A' + i))
f.SetColWidth(sheetName, col, col, 15)
}
f.SetColWidth(sheetName, "B", "B", 25) // Nome
f.SetColWidth(sheetName, "C", "C", 30) // Email
f.SetColWidth(sheetName, "G", "G", 40) // Notas
// Delete default sheet if exists
f.DeleteSheet("Sheet1")
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
w.Header().Set("Content-Disposition", "attachment; filename=leads.xlsx")
if err := f.Write(w); err != nil {
log.Printf("Error writing xlsx: %v", err)
}
}