publicando mudanças
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,212 @@
|
||||
# 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"""
|
||||
<html>
|
||||
<body>
|
||||
<p>{boa}</p>
|
||||
|
||||
<p>
|
||||
Segue o relatório semanal de Cobertura referente às regiões de
|
||||
Alagoas (AL), Bahia (BA), Sergipe (SE), Conquista (VDC), Bahia3(BA3).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Este relatório contempla exclusivamente os itens com cobertura superior à 60 dias.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Para mais informações, favor consultar a planilha em anexo.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
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.")
|
||||
Reference in New Issue
Block a user