# enviar_email_excel.py import smtplib import ssl import pyodbc import configparser import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates import matplotlib.ticker as mtick import seaborn as sns from email.message import EmailMessage from email.utils import make_msgid from email.mime.image import MIMEImage from pathlib import Path from datetime import datetime, time config = configparser.ConfigParser() config.read(r"credenciais.ini") excel_path = Path("relatorio.xlsx") print(config['banco']['host'],config['banco']['user'],config['banco']['password']) # Conexão com o banco conn = pyodbc.connect( f"DRIVER={{SQL Server}};" f"SERVER={config['banco']['host']},1433;" f"DATABASE=GINSENG;" f"UID={config['banco']['user']};" f"PWD={config['banco']['password']}") # 1. Criar dados fictícios e gerar Excel query = ''' WITH CTE_Estoque AS ( SELECT em.ORIGEM, em.PDV, CONCAT(em.PDV, em.ORIGEM) AS PDV_Origem, -- Coluna unificada CASE WHEN em.SKU_PARA IS NULL THEN em.SKU ELSE em.SKU_PARA END AS SKU_FINAL, em.DESCRICAO, em.CATEGORIA, em.CLASSE, CAST(REPLACE(em.[ESTOQUE ATUAL], ',', '.') AS FLOAT) AS [ESTOQUE ATUAL], CAST(REPLACE(em.[ESTOQUE EM TRANSITO], ',', '.') AS FLOAT) AS [ESTOQUE EM TRANSITO], CAST(REPLACE(em.[PEDIDO PENDENTE], ',', '.') AS FLOAT) AS [PEDIDO PENDENTE], CAST(REPLACE(em.[DDV PREVISTO], ',', '.') AS FLOAT) AS [DDV PREVISTO], ROUND( CAST(REPLACE(em.[ESTOQUE ATUAL], ',', '.') AS FLOAT) / NULLIF(CAST(REPLACE(em.[DDV PREVISTO], ',', '.') AS FLOAT), 0), 0 ) AS [Cobertura Atual], ROUND( (CAST(REPLACE(em.[ESTOQUE ATUAL], ',', '.') AS FLOAT) + CAST(REPLACE(em.[ESTOQUE EM TRANSITO], ',', '.') AS FLOAT) + CAST(REPLACE(em.[PEDIDO PENDENTE], ',', '.') AS FLOAT)) / NULLIF(CAST(REPLACE(em.[DDV PREVISTO], ',', '.') AS FLOAT), 0), 0 ) AS [Cobertura Projetada], d.preco_Compra, d.Dias_sem_Vendas, pr.ATUAL_PROMO , pr.PROX_PROMO FROM estoque_mar em LEFT JOIN ( SELECT d.loja_id AS PDV, d.code AS SKU, d.description AS Descricao, d.pricesellin AS preco_Compra, d.dayswithoutsales as Dias_sem_Vendas FROM draft d) d ON em.PDV = d.PDV AND (CASE WHEN em.SKU_PARA IS NULL THEN em.SKU ELSE em.SKU_PARA END) = CAST( d.SKU AS INT) LEFT JOIN ( SELECT p.loja_id AS PDV, p.code AS SKU, CASE WHEN STRING_AGG(p.currentCycle_description, ', ') IS NULL OR LTRIM(RTRIM( STRING_AGG(p.currentCycle_description, ', '))) = '' THEN 'Regular' ELSE 'Promocao' END AS ATUAL_PROMO, CASE WHEN STRING_AGG(p.nextCycle_description, ', ') IS NULL OR LTRIM(RTRIM(STRING_AGG(p.nextCycle_description, ', '))) = '' THEN 'Regular' ELSE 'Promocao' END AS PROX_PROMO FROM promo p WHERE P.created_at >= CAST(GETDATE() AS DATE) AND P.created_at < DATEADD(DAY, 1, CAST(GETDATE() AS DATE)) GROUP BY p.loja_id, p.code ) pr ON em.PDV = pr.PDV AND (CASE WHEN em.SKU_PARA IS NULL THEN em.SKU ELSE em.SKU_PARA END) = CAST(pr.SKU AS INT) WHERE em.CATEGORIA NOT IN ('SUPORTE À VENDA', 'EMBALAGENS') ) SELECT bpm.DESCRICAO AS DESCRICAO_PDV, bpm.UF, bpm.ANALISTA, cte.* FROM CTE_Estoque cte LEFT JOIN base_pdvs_marca bpm ON cte.PDV_Origem = bpm.PDV_MARCA -- agora join pelo unificado WHERE [Cobertura Atual] > 60; ''' df = pd.read_sql(query, conn) df.to_excel(excel_path,index=False) conn.close() print(df.columns) remetente = config['credenciais']['remetente'] senha = config['credenciais']['senha'] destinatarios = [email.strip() for email in config['email_cobertura']['destinatarios'].split(',')] assunto = config['email_cobertura']['assunto'] print(remetente,senha,destinatarios,assunto) # Obtém a hora atual agora = datetime.now().time() hoje = datetime.today().strftime("%d/%m/%Y") # Define os intervalos de tempo manhã_inicio = time(5, 0) manhã_fim = time(12, 0) tarde_inicio = time(12, 1) tarde_fim = time(18, 0) # noite é dividida em dois intervalos por causa da virada do dia noite_inicio = time(18, 1) noite_fim = time(4, 59) # Verifica em qual intervalo a hora atual está if manhã_inicio <= agora <= manhã_fim: boa = "Bom dia!" elif tarde_inicio <= agora <= tarde_fim: boa = "Boa tarde!" else: boa = "Boa noite!" # 3. Criar e-mail com imagem embutida msg = EmailMessage() msg['From'] = remetente msg['To'] = ', '.join(destinatarios) msg['Subject'] = assunto # 4. Conteúdo do e-mail html_email = f"""

{boa}

Segue o relatório semanal de Cobertura referente às regiões de Alagoas (AL), Bahia (BA), Sergipe (SE), Conquista (VDC), Bahia3(BA3).

Este relatório contempla exclusivamente os itens com cobertura superior à 60 dias.

O objetivo é trazer visibilidade para os produtos parados e reforçar a importância de ações para estimular a sua saída, contribuindo assim para a redução da cobertura de estoque e otimização dos recursos.

Contamos com o apoio de todos para análise e tratativa dos itens listados. Sugestões de ações como campanhas, transferências ou ajustes de sortimento são bem-vindas para acelerar a movimentação dos produtos.

Importante destacar que este relatório ainda não contempla as transferências realizadas internamente, uma vez que estamos trabalhando para viabilizar a inclusão dessas informações no banco de dados.

Para mais informações, favor consultar a planilha em anexo.

""" msg.set_content("Seu e-mail precisa de um visualizador HTML.") msg.add_alternative(html_email, subtype='html') # 5. Anexar o arquivo Excel with open(excel_path, 'rb') as f: msg.add_attachment( f.read(), maintype='application', subtype='vnd.openxmlformats-officedocument.spreadsheetml.sheet', filename=excel_path.name ) # 6. Enviar o e-mail via SMTP Outlook com configurações fornecidas with smtplib.SMTP('smtp-mail.outlook.com', 587) as smtp: smtp.ehlo() smtp.starttls(context=ssl.create_default_context()) smtp.login(remetente, senha) smtp.send_message(msg) print("E-mail enviado com sucesso.")