""" Utilidades de exportación para Sales Bot Genera archivos Excel y CSV con datos de ventas """ import csv import io from datetime import datetime try: from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side from openpyxl.utils import get_column_letter OPENPYXL_DISPONIBLE = True except ImportError: OPENPYXL_DISPONIBLE = False def generar_excel_ventas(ventas, vendedor, stats): """ Genera archivo Excel con múltiples hojas: - Resumen: Estadísticas generales - Ventas: Detalle de todas las ventas - Comisiones: Desglose de comisiones """ if not OPENPYXL_DISPONIBLE: raise ImportError("openpyxl no está instalado") wb = Workbook() # Estilos header_font = Font(bold=True, color='FFFFFF') header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid') header_alignment = Alignment(horizontal='center', vertical='center') currency_format = '$#,##0.00' thin_border = Border( left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin') ) # ==================== HOJA 1: RESUMEN ==================== ws_resumen = wb.active ws_resumen.title = "Resumen" # Título ws_resumen['A1'] = f"Reporte de Ventas - {vendedor}" ws_resumen['A1'].font = Font(bold=True, size=16) ws_resumen.merge_cells('A1:D1') ws_resumen['A2'] = f"Generado: {datetime.now().strftime('%Y-%m-%d %H:%M')}" ws_resumen['A2'].font = Font(italic=True, color='666666') # Estadísticas resumen_data = [ ['Métrica', 'Valor'], ['Total de Ventas', len(ventas)], ['Monto Total', stats.get('monto_total', 0) if stats else 0], ['Tubos Vendidos', stats.get('tubos_totales', 0) if stats else 0], ['Comisión Total', stats.get('comision_total', 0) if stats else 0], ['Días Activos', stats.get('dias_activos', 0) if stats else 0], ['Días con Meta Cumplida', stats.get('dias_meta_cumplida', 0) if stats else 0], ['Promedio Tubos/Día', round(stats.get('promedio_tubos_dia', 0), 1) if stats else 0], ] for row_idx, row_data in enumerate(resumen_data, start=4): for col_idx, value in enumerate(row_data, start=1): cell = ws_resumen.cell(row=row_idx, column=col_idx, value=value) cell.border = thin_border if row_idx == 4: # Header cell.font = header_font cell.fill = header_fill cell.alignment = header_alignment elif col_idx == 2 and row_idx in [6, 8]: # Montos cell.number_format = currency_format # Ajustar anchos ws_resumen.column_dimensions['A'].width = 25 ws_resumen.column_dimensions['B'].width = 15 # ==================== HOJA 2: VENTAS ==================== ws_ventas = wb.create_sheet("Ventas") headers_ventas = ['ID', 'Fecha', 'Cliente', 'Monto', 'Estado', 'Canal'] for col_idx, header in enumerate(headers_ventas, start=1): cell = ws_ventas.cell(row=1, column=col_idx, value=header) cell.font = header_font cell.fill = header_fill cell.alignment = header_alignment cell.border = thin_border for row_idx, venta in enumerate(ventas, start=2): fecha = venta.get('fecha_venta', '') if fecha: try: fecha = datetime.fromisoformat(fecha.replace('+00:00', '')).strftime('%Y-%m-%d %H:%M') except: pass row_data = [ venta.get('Id', ''), fecha, venta.get('cliente', ''), venta.get('monto', 0), venta.get('estado', ''), venta.get('canal', '') ] for col_idx, value in enumerate(row_data, start=1): cell = ws_ventas.cell(row=row_idx, column=col_idx, value=value) cell.border = thin_border if col_idx == 4: # Monto cell.number_format = currency_format # Ajustar anchos column_widths = [8, 18, 25, 12, 12, 15] for col_idx, width in enumerate(column_widths, start=1): ws_ventas.column_dimensions[get_column_letter(col_idx)].width = width # Agregar filtros ws_ventas.auto_filter.ref = f"A1:F{len(ventas) + 1}" # ==================== HOJA 3: COMISIONES ==================== ws_comisiones = wb.create_sheet("Comisiones") headers_comisiones = ['Descripción', 'Cantidad', 'Valor'] for col_idx, header in enumerate(headers_comisiones, start=1): cell = ws_comisiones.cell(row=1, column=col_idx, value=header) cell.font = header_font cell.fill = header_fill cell.alignment = header_alignment cell.border = thin_border meta_diaria = 3 comision_por_tubo = 10 tubos_totales = stats.get('tubos_totales', 0) if stats else 0 tubos_comisionables = max(0, tubos_totales - (meta_diaria * stats.get('dias_activos', 0))) if stats else 0 comisiones_data = [ ['Tubos vendidos', tubos_totales, ''], ['Meta diaria', meta_diaria, 'tubos'], ['Días activos', stats.get('dias_activos', 0) if stats else 0, 'días'], ['Tubos comisionables', tubos_comisionables, ''], ['Comisión por tubo', comision_por_tubo, ''], ['', '', ''], ['COMISIÓN TOTAL', stats.get('comision_total', 0) if stats else 0, ''], ] for row_idx, row_data in enumerate(comisiones_data, start=2): for col_idx, value in enumerate(row_data, start=1): cell = ws_comisiones.cell(row=row_idx, column=col_idx, value=value) cell.border = thin_border if row_idx == 8: # Total cell.font = Font(bold=True) if col_idx == 2: cell.number_format = currency_format elif col_idx == 2 and row_idx == 6: cell.number_format = currency_format # Ajustar anchos ws_comisiones.column_dimensions['A'].width = 20 ws_comisiones.column_dimensions['B'].width = 15 ws_comisiones.column_dimensions['C'].width = 10 # Guardar a bytes output = io.BytesIO() wb.save(output) output.seek(0) return output.getvalue() def generar_csv_ventas(ventas): """ Genera archivo CSV con el detalle de ventas. Formato simple compatible con cualquier aplicación. """ output = io.StringIO() fieldnames = ['id', 'fecha', 'cliente', 'monto', 'estado', 'canal', 'vendedor'] writer = csv.DictWriter(output, fieldnames=fieldnames) writer.writeheader() for venta in ventas: fecha = venta.get('fecha_venta', '') if fecha: try: fecha = datetime.fromisoformat(fecha.replace('+00:00', '')).strftime('%Y-%m-%d %H:%M') except: pass writer.writerow({ 'id': venta.get('Id', ''), 'fecha': fecha, 'cliente': venta.get('cliente', ''), 'monto': venta.get('monto', 0), 'estado': venta.get('estado', ''), 'canal': venta.get('canal', ''), 'vendedor': venta.get('vendedor_username', '') }) return output.getvalue().encode('utf-8') def generar_reporte_comisiones_csv(historial): """ Genera CSV con historial de comisiones. """ output = io.StringIO() fieldnames = ['mes', 'tubos', 'comision', 'ventas', 'dias_activos', 'monto_total'] writer = csv.DictWriter(output, fieldnames=fieldnames) writer.writeheader() for h in historial: writer.writerow({ 'mes': h.get('mes', ''), 'tubos': h.get('tubos_totales', 0), 'comision': h.get('comision_total', 0), 'ventas': h.get('cantidad_ventas', 0), 'dias_activos': h.get('dias_activos', 0), 'monto_total': h.get('monto_total', 0) }) return output.getvalue().encode('utf-8')