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) } }