211 lines
5.0 KiB
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)
|
|
}
|
|
}
|