Compare commits

...

6 Commits

Author SHA1 Message Date
João Herculano
22cc3883c3 atualizações 04/09 2025-09-04 12:29:39 -03:00
João Herculano
846c8e83e6 publicando mudanças 2025-08-26 13:57:11 -03:00
João Herculano
05e7958878 Nova versão com VDC funcionando 2025-08-15 15:50:12 -03:00
João Herculano
0dc3604b19 mudança na promoção pro banco de dados 2025-07-29 14:33:40 -03:00
João Herculano
2d30118d6a mudanças pra gerar a c11 2025-06-23 14:30:35 -03:00
João Herculano
daee7ec309 mudanças de arquivos para a mesma pasta 2025-06-20 11:22:28 -03:00
26 changed files with 19522 additions and 2407 deletions

View File

@ -0,0 +1,231 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "e9ac37de",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total de linhas: 875\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>UN</th>\n",
" <th>PDV</th>\n",
" <th>CIDADE</th>\n",
" <th>LOCAL DO PDV</th>\n",
" <th>RECEITA PERÍODO ANTERIOR</th>\n",
" <th>RECEITA PERÍODO ATUAL</th>\n",
" <th>META PEF</th>\n",
" <th>GAP ACORDADO (R$)</th>\n",
" <th>GAP ACORDADO (%)</th>\n",
" <th>REALIZADO</th>\n",
" <th>arquivo_base</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Quem Disse Berenice</td>\n",
" <td>910173</td>\n",
" <td>Maceio</td>\n",
" <td>Shopping</td>\n",
" <td>173913.81</td>\n",
" <td>0</td>\n",
" <td>167464.53</td>\n",
" <td>-167464.53</td>\n",
" <td>-1</td>\n",
" <td>0</td>\n",
" <td>C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>O Boticário</td>\n",
" <td>21381</td>\n",
" <td>Capim Grosso</td>\n",
" <td>Rua</td>\n",
" <td>120594.40</td>\n",
" <td>0</td>\n",
" <td>155346.60</td>\n",
" <td>-155346.60</td>\n",
" <td>-1</td>\n",
" <td>0</td>\n",
" <td>C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>O Boticário</td>\n",
" <td>23707</td>\n",
" <td>Vitoria Da Conquista</td>\n",
" <td>Rua</td>\n",
" <td>131055.70</td>\n",
" <td>0</td>\n",
" <td>159139.40</td>\n",
" <td>-159139.40</td>\n",
" <td>-1</td>\n",
" <td>0</td>\n",
" <td>C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>O Boticário</td>\n",
" <td>21068</td>\n",
" <td>Simoes Filho</td>\n",
" <td>Cash &amp; Carry</td>\n",
" <td>146448.38</td>\n",
" <td>0</td>\n",
" <td>144695.45</td>\n",
" <td>-144695.45</td>\n",
" <td>-1</td>\n",
" <td>0</td>\n",
" <td>C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>O Boticário</td>\n",
" <td>20441</td>\n",
" <td>Lagarto</td>\n",
" <td>Rua</td>\n",
" <td>225341.32</td>\n",
" <td>0</td>\n",
" <td>311878.51</td>\n",
" <td>-311878.51</td>\n",
" <td>-1</td>\n",
" <td>0</td>\n",
" <td>C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên...</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" UN PDV CIDADE LOCAL DO PDV \\\n",
"0 Quem Disse Berenice 910173 Maceio Shopping \n",
"1 O Boticário 21381 Capim Grosso Rua \n",
"2 O Boticário 23707 Vitoria Da Conquista Rua \n",
"3 O Boticário 21068 Simoes Filho Cash & Carry \n",
"4 O Boticário 20441 Lagarto Rua \n",
"\n",
" RECEITA PERÍODO ANTERIOR RECEITA PERÍODO ATUAL META PEF \\\n",
"0 173913.81 0 167464.53 \n",
"1 120594.40 0 155346.60 \n",
"2 131055.70 0 159139.40 \n",
"3 146448.38 0 144695.45 \n",
"4 225341.32 0 311878.51 \n",
"\n",
" GAP ACORDADO (R$) GAP ACORDADO (%) REALIZADO \\\n",
"0 -167464.53 -1 0 \n",
"1 -155346.60 -1 0 \n",
"2 -159139.40 -1 0 \n",
"3 -144695.45 -1 0 \n",
"4 -311878.51 -1 0 \n",
"\n",
" arquivo_base \n",
"0 C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên... \n",
"1 C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên... \n",
"2 C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên... \n",
"3 C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên... \n",
"4 C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistên... "
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import os\n",
"import pandas as pd\n",
"import glob\n",
"\n",
"# Caminho da pasta onde estão os arquivos\n",
"pasta = r'C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\DB_ORÇAMENTO FIANCEIRO\\meta pef baixada hj'\n",
"\n",
"# Lista todos os arquivos .xlsx no diretório\n",
"arquivos_xlsx = glob.glob(os.path.join(pasta, '*.xlsx'))\n",
"\n",
"# Lista para armazenar os DataFrames\n",
"dfs = []\n",
"\n",
"# Loop pelos arquivos encontrados\n",
"for arquivo in arquivos_xlsx:\n",
" try:\n",
" df = pd.read_excel(arquivo, sheet_name='PERFORMANCE POR PDV', skiprows=2)\n",
" df['arquivo_base'] = arquivo\n",
" dfs.append(df)\n",
" except Exception as e:\n",
" print(f\"Erro ao ler {arquivo}: {e}\")\n",
"\n",
"# Concatena todos os DataFrames\n",
"compilado_pef = pd.concat(dfs, ignore_index=True)\n",
"\n",
"# Exibe informações do DataFrame final\n",
"print(f\"Total de linhas: {len(compilado_pef)}\")\n",
"compilado_pef.head()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "40a4ace1",
"metadata": {},
"outputs": [],
"source": [
"compilado_pef.to_excel(r'C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\DB_ORÇAMENTO FIANCEIRO\\PEF_ATUALIZADA.xlsx',index=False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "949b7fdc",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -0,0 +1,901 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "4dda0350",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np \n",
"import glob\n",
"import os "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4d6a9919",
"metadata": {},
"outputs": [],
"source": [
"# Caminho onde estão as subpastas com os arquivos CSV\n",
"\n",
"# Set the path to the folder containing CSV files\n",
"folder_path = r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\EUDORA\\C10\\draft\" # arquivo dos drafts\n",
"\n",
"# Pattern to match all CSV files\n",
"csv_files = glob.glob(os.path.join(folder_path, '*.csv'))\n",
"\n",
"# Read and concat all CSVs\n",
"df_draft = pd.concat([pd.read_csv(file) for file in csv_files], ignore_index=True)\n",
"\n",
"df_draft['match'] = 1 \n",
"\n",
"df_draft.shape\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aa56ee52",
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n",
"# Caminho onde estão as subpastas com os arquivos CSV\n",
"pasta_entrada = r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\EUDORA\\C10\\estoque\"\n",
"\n",
"# Lista todas as subpastas dentro de \"ESTOQUE\"\n",
"subpastas = [os.path.join(pasta_entrada, d) for d in os.listdir(pasta_entrada) if os.path.isdir(os.path.join(pasta_entrada, d))]\n",
"\n",
"df_list = []\n",
"\n",
"# Percorre todas as subpastas\n",
"for subpasta in subpastas:\n",
" arquivos = [f for f in os.listdir(subpasta) if f.endswith(\".csv\")]\n",
" nome_pasta = os.path.basename(subpasta) # Obtém o nome da pasta\n",
"\n",
" for arquivo in arquivos:\n",
" caminho_arquivo = os.path.join(subpasta, arquivo)\n",
" try:\n",
" df = pd.read_csv(caminho_arquivo, encoding=\"utf-8\", low_memory=False) # Melhor para grandes volumes de dados\n",
" df[\"Arquivo_Origem\"] = arquivo # Adiciona o nome do arquivo de origem\n",
" df[\"Pasta_Origem\"] = nome_pasta # Adiciona o nome da pasta de origem\n",
" df_list.append(df)\n",
" except Exception as e:\n",
" print(f\"Erro ao ler o arquivo {arquivo}: {e}\")\n",
"\n",
"if df_list:\n",
" df_estoque = pd.concat(df_list, ignore_index=True)\n",
"\n",
"df_estoque['PDV'] = df_estoque['PDV'].astype(str)\n",
"\n",
"df_estoque['SKU_FINAL'] = np.where(df_estoque['SKU_PARA'] == \"-\", df_estoque['SKU'], df_estoque['SKU_PARA'])\n",
"\n",
"df_estoque['SKU_FINAL']=df_estoque['SKU_FINAL'].astype(str)\n",
"\n",
"df_estoque = df_estoque[df_estoque['Arquivo_Origem']== \"EUD.csv\"]\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "db3b7495",
"metadata": {},
"outputs": [],
"source": [
"df_bi_vendas = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\EUDORA\\C10\\data (1).xlsx\")\n",
"\n",
"df_bi_vendas['Ciclo_ultimos2'] = df_bi_vendas['Ciclo'].str.rsplit('.', n=1).str[-1]\n",
"\n",
"df_bi_vendas['Ciclo_ano'] = df_bi_vendas['Ciclo'].str.rsplit('.', n=1).str[0]\n",
"\n",
"df_bi_vendas['Ciclo_ano'] = df_bi_vendas['Ciclo_ano'].str.replace(\"C\",\"\")\n",
"\n",
"df_bi_vendas['CICLO_FINAL'] = 'C20' + df_bi_vendas['Ciclo_ano'].astype(str) + df_bi_vendas['Ciclo_ultimos2'].astype(str)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dbd61b6a",
"metadata": {},
"outputs": [],
"source": [
"df_pdv = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\EUDORA\\PDV\\DB_PDV.xlsx\",sheet_name='Export')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29504e7c",
"metadata": {},
"outputs": [],
"source": [
"df_pdv = df_pdv.rename(columns={'DESCRIÇÃO':'DESCRIÇÃO PDV'})\n",
"\n",
"df_pdv = df_pdv.drop(columns=['REGIÃO', 'ESTADO','CIDADE','GESTÃO'])\n",
"\n",
"df_pdv['PDV'] = df_pdv['PDV DESC'].str.split(\"-\").str[0].str.strip()\n",
"\n",
"df_pdv['UF'] = np.where(df_pdv['UF'] == 'VDC','BA',df_pdv['UF'])\n",
"\n",
"#ignorando a PDV que ainda não está online\n",
"df_pdv = df_pdv[df_pdv['DESCRIÇÃO PDV'] != '23813-COMERCIO-HIB VALENTE']\n",
"df_pdv = df_pdv[df_pdv['STATUS'] == 'ATIVO']\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae39bc1e",
"metadata": {},
"outputs": [],
"source": [
"calendario = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\EUDORA\\CALENDARIO_CICLO\\Ciclo_Expandido_com_Datas.xlsx\")\n",
"\n",
"calendario['Date'] = pd.to_datetime(calendario['Date'])\n",
"\n",
"# Get today (normalized to midnight)\n",
"today = pd.Timestamp(\"today\").normalize()\n",
"\n",
"calendario['NUM_CICLO'] = calendario['Ciclo'].str[-2:].astype(int)\n",
"\n",
"calendario['ANO_CICLO'] = calendario['Ciclo'].str[0:5]\n",
"\n",
"calendario = calendario[calendario['MARCA'] == \"EUDORA\"]\n",
"\n",
"calendario['CICLOMAIS2'] = calendario['ANO_CICLO'].astype(str) + (calendario['NUM_CICLO'].astype(int) + 3).astype(str).str.zfill(2) #<<< MUDAR O \"4\" (CICLO ATUAL + 4 PARA ACHAR O CICLO DA SUGESTÃO) EX: C202505 -> C202509\n",
"ciclo_mais2 = calendario[calendario['Date'].dt.normalize() == today]['CICLOMAIS2'].iloc[0]\n",
"\n",
"# Filter rows where date matches today\n",
"filtered_calendario = calendario[calendario['Ciclo'] == ciclo_mais2][:1]\n",
"\n",
"filtered_calendario['dias_ate_inicio'] = filtered_calendario['INICIO CICLO'].iloc[0] - today\n",
"\n",
"filtered_calendario['dias_ate_inicio'] = filtered_calendario['dias_ate_inicio'].dt.days.astype(int)\n",
"\n",
"filtered_calendario['match'] = 1\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5ac3914a",
"metadata": {},
"outputs": [],
"source": [
"#df_tabela = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\EUDORA\\TABELA_PEDIDO\\Pedidos Semanais Especiais - GKD - 202509.xlsx\")\n",
"\n",
"#df_tabela = df_tabela[df_tabela['Região'] == 'NNE'] \n",
"\n",
"#df_tabela = df_tabela[(df_tabela['Canal'] != 'Ecomm') | (df_tabela['Canal'] != 'Ecomm | VD') | (df_tabela['Canal'] != 'Ecomm | Loja')] #perguntar se isso aqui é vdd\n",
"\n",
"#df_tabela['Canal'] = np.where((df_tabela['Canal'] == \"Loja\") | (df_tabela['Canal'] == \"Todos\") | (df_tabela['Canal'] == \"Loja | VD\"),\"TODOS\",\"VD\")\n",
"\n",
"#df_tabela = df_tabela[df_tabela['Tipo de promoção'].str.contains('Lançamentos', na=False)]#"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f8ea9d1a",
"metadata": {},
"outputs": [],
"source": [
"df_tabela = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\EUDORA\\C10\\Tabela-de-Promos_C10-1746728296536.xlsx (1).xlsx\")\n",
"\n",
"df_tabela = df_tabela[['Código do Item','Descrição do Item','Chamada Promocional','Valor do Guia','Preço Promocionado','% de Desconto']]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1a338b98",
"metadata": {},
"outputs": [],
"source": [
"df_similares = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\EUDORA\\C10\\PRODUTOS SIMILARES.xlsx\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39ddc830",
"metadata": {},
"outputs": [],
"source": [
"df_similares = pd.merge(left=df_similares,right=calendario[['Ciclo','INICIO CICLO','FIM CICLO','DURAÇÃO']], how= 'left', left_on = 'CICLO SIMILAR',right_on = 'Ciclo' )\n",
"\n",
"df_similares = df_similares.drop(columns=['INICIO DO CICLO SIMILAR','FIM DO CICLO SIMILAR', 'DURAÇÃO DO CICLO DO SIMILAR','Ciclo','DESCRIÇÃO SIMILAR'])\n",
"\n",
"df_similares = df_similares.rename(columns={'INICIO CICLO':'INICIO CICLO SIMILAR','FIM CICLO':'FIM CICLO SIMILAR','DURAÇÃO':'DURAÇÃO CICLO SIMILAR'})\n",
"df_similares.drop_duplicates(inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2eb0975",
"metadata": {},
"outputs": [],
"source": [
"df_draft = df_draft.rename(columns={'Descrição':'DESCRIÇÃO SIMILAR'})\n",
"\n",
"df_draft = df_draft.drop(columns=['Categoria','Subcategoria', 'Lançamento', 'Desativação',\n",
" 'Dias sem venda','Projeção Próximo Ciclo', 'Projeção Próximo Ciclo + 1',\n",
" 'Promoção Próximo Ciclo', 'Promoção Próximo Ciclo + 1','Compra inteligente semanal/Sugestão de compra',\n",
" 'Compra inteligente Próximo Ciclo',\n",
" 'Compra inteligente Próximo Ciclo + 1', 'Item Desativado',\n",
" 'Data Prevista Regularização', 'Carteira Bloqueada Para Novos Pedidos',\n",
" 'Planograma', 'Quantidade por caixa', 'Preço Sell In','Item analisado', 'Histórico de Vendas do Ciclo 202505'])\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c6d00ef5",
"metadata": {},
"outputs": [],
"source": [
"caminho_pasta = r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\EUDORA\\C10\\venda_pratico\"\n",
"\n",
"# Lista todos os arquivos Excel na pasta\n",
"arquivos_excel = [\n",
" f for f in os.listdir(caminho_pasta)\n",
" if f.lower().endswith(('.xlsx', '.xls'))\n",
"]\n",
"caminho_arquivo = os.path.join(caminho_pasta, arquivos_excel[0])\n",
"\n",
"df_venda_diaria = pd.read_excel(caminho_arquivo)\n",
"\n",
"df_venda_diaria.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a82629ba",
"metadata": {},
"outputs": [],
"source": [
"df_venda_diaria['PDV'] = df_venda_diaria['Unidade de Negócio'].str.split(\"-\").str[0].str.strip()\n",
"\n",
"df_venda_diaria['Dia'] = pd.to_datetime(df_venda_diaria['Dia'], format='%d/%m/%Y')\n",
"\n",
"df_venda_diaria = pd.merge(left=df_venda_diaria,right=calendario[['Ciclo','Date']],left_on='Dia',right_on='Date',how='inner')\n",
"\n",
"df_venda_diaria = df_venda_diaria.drop(columns='Date')\n",
"\n",
"df_venda_diaria.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4cd37229",
"metadata": {},
"outputs": [],
"source": [
"df_venda_diaria = df_venda_diaria.drop_duplicates()\n",
"\n",
"df_venda_diaria.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15773282",
"metadata": {},
"outputs": [],
"source": [
"df_venda_agrupado = df_venda_diaria.groupby(['PDV', 'Código do Produto','Ciclo'])['Quantidade'].sum().reset_index()\n",
"df_venda_agrupado['Quantidade'].value_counts()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "11a29a22",
"metadata": {},
"outputs": [],
"source": [
"df_pdv['match'] = 1\n",
"\n",
"df_similares['match'] = 1"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7f9ff38f",
"metadata": {},
"outputs": [],
"source": [
"df_final = pd.merge(left=df_similares,right=df_pdv, on='match',how='inner')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "63c52601",
"metadata": {},
"outputs": [],
"source": [
"df_draft['PDV'] = df_draft['PDV'].astype(str)\n",
"df_final = pd.merge(left=df_final,right=df_draft,right_on=['SKU','PDV'],left_on=['PRODUTO SIMILAR','PDV'],how='left')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6dcc2058",
"metadata": {},
"outputs": [],
"source": [
"df_similares['MATCH'] = 1 \n",
"df_pdv['MATCH'] = 1\n",
"\n",
"df_temp = pd.merge(right=df_similares[['PRODUTO LANÇAMENTO', 'DESCRIÇÃO DO LANÇAMENTO','MATCH']],left=df_pdv, on= 'MATCH',how='inner')\n",
"df_temp = df_temp.drop_duplicates()\n",
"\n",
"df_temp"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "90a54c84",
"metadata": {},
"outputs": [],
"source": [
"df_final['match'] = 1\n",
"df_final['match'] = df_final['match'].astype(int)\n",
"df_final = pd.merge(left=df_final, right=filtered_calendario[['Ciclo','INICIO CICLO','FIM CICLO','DURAÇÃO','match','dias_ate_inicio']], right_on='match',left_on='match',how='inner')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15b16b69",
"metadata": {},
"outputs": [],
"source": [
"#df_final['PDV'] = df_final['PDV'].astype(str)\n",
"\n",
"#df_final = pd.merge(left=df_final,right=df_pdv[['PDV', 'CANAL', 'DESCRIÇÃO PDV', 'PDV DESC','UF','ANALISTA','SUPERVISOR']],on = 'PDV',how='inner')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a453dc4",
"metadata": {},
"outputs": [],
"source": [
"df_bi_vendas = df_bi_vendas.rename(columns={'Quantidade':'Vendas Ciclo Lançamento'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a2a92cc7",
"metadata": {},
"outputs": [],
"source": [
"df_bi_vendas['PDV'] = df_bi_vendas['PDV'].astype(str) \n",
"df_bi_vendas['SKU2'] = df_bi_vendas['SKU2'].astype(str) \n",
"\n",
"df_final['PRODUTO SIMILAR'] = df_final['PRODUTO SIMILAR'].astype(str)\n",
"\n",
"df_final['SKU'] = df_final['SKU'].astype(str)\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_bi_vendas,right_on=['PDV','SKU2','CICLO_FINAL'],left_on=['PDV','PRODUTO SIMILAR','CICLO SIMILAR'],how='left')\n",
"df_final.shape "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b8cf0aa0",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns='Quantidade') "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "085cde87",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['SKU','match',\n",
" 'Ciclo_y',\n",
" 'SKU1', 'SKU2', 'Campanha','TOTAL PV',\n",
" 'Ciclo_ultimos2', 'Ciclo_ano', 'CICLO_FINAL'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "57d4871f",
"metadata": {},
"outputs": [],
"source": [
"df_final['CANAL'] = np.where((df_final['CANAL'] == 'LJ') | (df_final['CANAL'] == 'HIB'), \"TODOS\" , np.where((df_final['CANAL'] == 'CD') | (df_final['CANAL'] == 'VD'), \"VD\", df_final['CANAL']))\n",
"\n",
"df_final['CANAL'].value_counts()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e4e5868e",
"metadata": {},
"outputs": [],
"source": [
"df_tabela['Código do Item'] = df_tabela['Código do Item'].astype(str).str.replace('.0','',regex=False)\n",
"df_final['PRODUTO LANÇAMENTO'] = df_final['PRODUTO LANÇAMENTO'].astype(str)\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_tabela,right_on=['Código do Item'],left_on=['PRODUTO LANÇAMENTO'],how='left')\n",
"df_final.shape "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d6b65a39",
"metadata": {},
"outputs": [],
"source": [
"df_estoque = df_estoque.rename(columns={'SKU_FINAL':'SKU_PARA_VALIDACAO'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aaa90522",
"metadata": {},
"outputs": [],
"source": [
"df_final = pd.merge( left= df_final, right = df_estoque[['SKU_PARA_VALIDACAO','Arquivo_Origem','PDV']], left_on= ['PRODUTO SIMILAR','PDV'], right_on=['SKU_PARA_VALIDACAO','PDV'], how='left')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94f1a76f",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=[\n",
"'SKU_PARA_VALIDACAO'\n",
"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "efa6b757",
"metadata": {},
"outputs": [],
"source": [
"df_final['PDV_SKU'] = df_final['PDV'].astype(str) + df_final['PRODUTO SIMILAR'].astype(str) \n",
"\n",
"df_final['UFPRODUTO'] = df_final['UF'].astype(str) + df_final['PRODUTO SIMILAR'].astype(str)\n",
"\n",
"\n",
"VENDA_SIMILAR_6_MESES= df_final.columns[22:28]\n",
"\n",
"df_final['Pico Vendas Similar Ultimos 6 ciclos'] = df_final[VENDA_SIMILAR_6_MESES].max(axis=1)\n",
"\n",
"df_final = df_final.drop_duplicates()\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f10b3982",
"metadata": {},
"outputs": [],
"source": [
"df_venda_agrupado['Código do Produto'] = df_venda_agrupado['Código do Produto'].astype(str)\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_venda_agrupado,right_on=['PDV','Código do Produto','Ciclo'],left_on=['PDV','PRODUTO SIMILAR','CICLO SIMILAR'],how='left')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f96e45b",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['Ciclo','Código do Produto','Vendas Ciclo Lançamento'])\n",
"\n",
"df_final = df_final.rename(columns={'Quantidade':'Vendas Ciclo Lançamento'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "596cd352",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns[24:41]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41c64323",
"metadata": {},
"outputs": [],
"source": [
"# Suponha que os meses estão nas colunas 10 a 26 (17 colunas = 17 meses)\n",
"colunas_mensais = df_final.columns[24:41]\n",
"\n",
"# Passo 1: Soma todas as linhas (itens) por mês → resultado: total por mês\n",
"soma_mensal = df_final[colunas_mensais].sum()\n",
"\n",
"# Passo 2: Calcula a variação percentual de um mês para o outro\n",
"variacao_mensal = soma_mensal.pct_change()\n",
"\n",
"# Passo 3: Calcula a média da variação (ignorando o primeiro NaN)\n",
"media_variacao = variacao_mensal[1:].mean()\n",
"\n",
"# Calcula média e desvio padrão\n",
"media = variacao_mensal.mean()\n",
"desvio = variacao_mensal.std()\n",
"\n",
"# Define limite (ex: 2 desvios padrão)\n",
"limite_superior = media + 2 * desvio\n",
"limite_inferior = media - 2 * desvio\n",
"\n",
"# Filtra dados dentro do limite\n",
"filtro = variacao_mensal.between(limite_inferior, limite_superior)\n",
"df_filtrado = variacao_mensal[filtro]\n",
"CRESCIMENTO = round(df_filtrado.mean(),4)\n",
"\n",
"df_final['CRESCIMENTO'] = CRESCIMENTO\n",
"\n",
"CRESCIMENTO\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f32d8326",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns[28:29]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3c027cfc",
"metadata": {},
"outputs": [],
"source": [
"venda_similar_mesmo_ciclo_ano_passado = df_final.columns[28:29] #<<<<<<< CICLO ATUAL É [10:11]\n",
"ciclo_ano_passado = df_final.columns[18:19].str.split(\" \")[0][-1]\n",
"df_final[ciclo_ano_passado] = df_final[venda_similar_mesmo_ciclo_ano_passado]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "28f74b58",
"metadata": {},
"outputs": [],
"source": [
"df_final['Vendas Ciclo Lançamento'] = df_final['Vendas Ciclo Lançamento'].fillna(0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "58642d77",
"metadata": {},
"outputs": [],
"source": [
"vendas_todos_historicos = df_final.columns[24:40]\n",
"\n",
"df_final['MEDIANA DO HISTÓRICO'] = df_final[vendas_todos_historicos].median(axis=1)\n",
"\n",
"df_final['MEDIANA DO HISTÓRICO'] = np.where((df_final['MEDIANA DO HISTÓRICO']<1) & (df_final['MEDIANA DO HISTÓRICO'] >0),1,df_final['MEDIANA DO HISTÓRICO'] )#validar se foi\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "69473155",
"metadata": {},
"outputs": [],
"source": [
"crescimento = df_final['CRESCIMENTO']\n",
"vendas_lanc = df_final['Vendas Ciclo Lançamento']\n",
"pico_similar = df_final['Pico Vendas Similar Ultimos 6 ciclos']\n",
"mediana_hist = df_final['MEDIANA DO HISTÓRICO']\n",
"\n",
"# Primeiro cálculo intermediário\n",
"calc_lanc = crescimento * vendas_lanc + vendas_lanc\n",
"calc_pico = crescimento * pico_similar + pico_similar\n",
"\n",
"df_final['PV GINSENG'] = np.where(\n",
" calc_lanc != 0,\n",
" round(calc_lanc, 0),\n",
" np.where(\n",
" mediana_hist > 0,\n",
" round(crescimento * mediana_hist + mediana_hist,0),\n",
" round(calc_pico/2, 0)\n",
" )\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ea512a48",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns[39]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3cf3efe7",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.rename(columns={df_final.columns[36]: \"C-4\", df_final.columns[37]: \"C-3\",df_final.columns[38]: \"C-2\",df_final.columns[39]: \"C-1\"})\n",
"\n",
"df_final.drop(columns=df_final.columns[28:35], inplace=True)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b8b3551",
"metadata": {},
"outputs": [],
"source": [
"\n",
"marca_promo = df_estoque['Arquivo_Origem'].iloc[0].replace('.csv','')\n",
"\n",
"df_final['INICIO CICLO'] = pd.to_datetime(df_final['INICIO CICLO'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"df_final['FIM CICLO'] = pd.to_datetime(df_final['FIM CICLO'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"df_final['INICIO CICLO SIMILAR'] = pd.to_datetime(df_final['INICIO CICLO SIMILAR'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"df_final['FIM CICLO SIMILAR'] = pd.to_datetime(df_final['FIM CICLO SIMILAR'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"\n",
"\n",
"df_final = df_final.rename(columns={'Ciclo_x': 'Ciclo'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "93b589d9",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "43f96709",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['CRESCIMENTO','dias_ate_inicio','UFPRODUTO','Arquivo_Origem','UFPRODUTO','Código do Item','PDV_SKU',\n",
" 'FIM DO CICLO','INICIO DO CICLO','DURAÇÃO CICLO'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "edd78734",
"metadata": {},
"outputs": [],
"source": [
"df_final = pd.merge(left=df_final,right=df_pdv[['PDV','CANAL','UF']],how='inner',on='PDV')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7ac9e24c",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9c4cbae7",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['CANAL_x'])\n",
"\n",
"df_final = df_final.rename(columns={'CANAL_y':'CANAL', 'UF_y':'UF'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7d904672",
"metadata": {},
"outputs": [],
"source": [
"# Columns to bring up front\n",
"priority_cols = [\n",
" 'Ciclo','INICIO CICLO','FIM CICLO','ANALISTA','SUPERVISOR','UF','CANAL','PDV', 'DESCRIÇÃO PDV','DURAÇÃO',\t\n",
" 'PRODUTO LANÇAMENTO','DESCRIÇÃO DO LANÇAMENTO',\n",
" 'PRODUTO SIMILAR','DESCRIÇÃO SIMILAR','CICLO SIMILAR','INICIO CICLO SIMILAR','FIM CICLO SIMILAR','Estoque Atual',\n",
" 'Estoque em Transito',\t'Pedido Pendente',\n",
"\t'C-4',\t'C-3',\t'C-2',\t'C-1'\n",
"]\n",
"\n",
"# All remaining columns\n",
"other_cols = [col for col in df_final.columns if col not in priority_cols]\n",
"\n",
"# Reorder\n",
"df_final = df_final[priority_cols + other_cols]\n",
"\n",
"df_final['SUGESTÃO ABTASTECIMENTO'] = ''\n",
"\n",
"df_final['VENDAS R$ ABASTECIMENTO'] = ''\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d817ecd",
"metadata": {},
"outputs": [],
"source": [
"colunas_usadas = ['PDV', 'PRODUTO LANÇAMENTO', '% de Desconto', 'Chamada Promocional']\n",
"df_temp = df_final[[col for col in colunas_usadas if col in df_final.columns]].copy()\n",
"\n",
"# Agrupa por PDV e PRODUTO LANÇAMENTO\n",
"agrupado = df_temp.groupby(['PDV', 'PRODUTO LANÇAMENTO'], dropna=False).agg({\n",
" '% de Desconto': lambda x: list(pd.unique(x.dropna())),\n",
" 'Chamada Promocional': lambda x: list(pd.unique(x.dropna())),\n",
"}).reset_index()\n",
"\n",
"# Expande para colunas fixas com nomes novos e valores em branco se vazio\n",
"for i in range(4):\n",
" agrupado[f'% de desconto_{i+1}'] = agrupado['% de Desconto'].apply(lambda x: x[i] if len(x) > i else '')\n",
" agrupado[f'Mecanica de desconto_{i+1}'] = agrupado['Chamada Promocional'].apply(lambda x: x[i] if len(x) > i else '')\n",
"\n",
"# Remove as colunas de lista original\n",
"agrupado = agrupado.drop(columns=['% de Desconto', 'Chamada Promocional'])\n",
"\n",
"# Junta ao df_final\n",
"colunas_merge = ['PDV', 'PRODUTO LANÇAMENTO']\n",
"df_final = df_final.merge(agrupado, on=colunas_merge, how='left')\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "446d0d5b",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['Chamada Promocional','Preço Promocionado','% de Desconto','Descrição do Item','TIPO PRODUTO'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "922d2af3",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop_duplicates()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "92d051d8",
"metadata": {},
"outputs": [],
"source": [
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "08faefd9",
"metadata": {},
"outputs": [],
"source": [
"\n",
"from openpyxl import load_workbook\n",
"from openpyxl.styles import PatternFill, Font\n",
"\n",
"\n",
"# Export to Excel\n",
"output_file = f'C:\\\\Users\\\\joao.herculano\\\\Documents\\\\Lançamento_{marca_promo}_{ciclo_mais2}COMPLEMENTO.xlsx'\n",
"with pd.ExcelWriter(output_file, engine='openpyxl') as writer:\n",
" df_final.to_excel(writer, index=False, sheet_name='Sheet1')\n",
"\n",
"# Apply styles\n",
"wb = load_workbook(output_file)\n",
"ws = wb['Sheet1']\n",
"\n",
"# Style header\n",
"header_fill = PatternFill(start_color='ADD8E6', end_color='ADD8E6', fill_type='solid') # Light Blue\n",
"header_font = Font(color='FFFFFF', bold=True) # White & Bold\n",
"\n",
"for cell in ws[1]:\n",
" cell.fill = header_fill\n",
" cell.font = header_font\n",
"\n",
"# Style rows: gray/white alternating\n",
"gray_fill = PatternFill(start_color='DDDDDD', end_color='DDDDDD', fill_type='solid') # Light gray\n",
"\n",
"for i, row in enumerate(ws.iter_rows(min_row=2, max_row=ws.max_row), start=2):\n",
" if i % 2 == 0:\n",
" for cell in row:\n",
" cell.fill = gray_fill\n",
"\n",
"# Save styled workbook\n",
"wb.save(output_file)\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,949 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "4dda0350",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np \n",
"import glob\n",
"import os "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4d6a9919",
"metadata": {},
"outputs": [],
"source": [
"# Caminho onde estão as subpastas com os arquivos CSV\n",
"\n",
"# Set the path to the folder containing CSV files\n",
"folder_path = r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\DRAFT_HISTÓRICO DE VENDAS_MAR\" # arquivo dos drafts\n",
"\n",
"# Pattern to match all CSV files\n",
"csv_files = glob.glob(os.path.join(folder_path, '*.csv'))\n",
"\n",
"# Read and concat all CSVs\n",
"df_draft = pd.concat([pd.read_csv(file) for file in csv_files], ignore_index=True)\n",
"\n",
"df_draft['match'] = 1 \n",
"\n",
"df_draft.shape\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9fdbd4df",
"metadata": {},
"outputs": [],
"source": [
"df_draft.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e72bee99",
"metadata": {},
"outputs": [],
"source": [
"#df_draft = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\DRAFT_HISTÓRICO DE VENDAS_MAR\\pegou em excel\\DRAFT_PDVS_SEM_23701-20992_20250423090756.xlsx\",sheet_name='BOTICARIO')\n",
"\n",
"\n",
"#df_draft['match'] = 1 \n",
"\n",
"#df_draft.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7d0f7992",
"metadata": {},
"outputs": [],
"source": [
"df_draft = df_draft.drop(columns='Quantidade')\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aa56ee52",
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n",
"# Caminho onde estão as subpastas com os arquivos CSV\n",
"pasta_entrada = r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\ESTOQUE_ATUAL\"\n",
"\n",
"# Lista todas as subpastas dentro de \"ESTOQUE\"\n",
"subpastas = [os.path.join(pasta_entrada, d) for d in os.listdir(pasta_entrada) if os.path.isdir(os.path.join(pasta_entrada, d))]\n",
"\n",
"df_list = []\n",
"\n",
"# Percorre todas as subpastas\n",
"for subpasta in subpastas:\n",
" arquivos = [f for f in os.listdir(subpasta) if f.endswith(\".csv\")]\n",
" nome_pasta = os.path.basename(subpasta) # Obtém o nome da pasta\n",
"\n",
" for arquivo in arquivos:\n",
" caminho_arquivo = os.path.join(subpasta, arquivo)\n",
" try:\n",
" df = pd.read_csv(caminho_arquivo, encoding=\"utf-8\", low_memory=False) # Melhor para grandes volumes de dados\n",
" df[\"Arquivo_Origem\"] = arquivo # Adiciona o nome do arquivo de origem\n",
" df[\"Pasta_Origem\"] = nome_pasta # Adiciona o nome da pasta de origem\n",
" df_list.append(df)\n",
" except Exception as e:\n",
" print(f\"Erro ao ler o arquivo {arquivo}: {e}\")\n",
"\n",
"if df_list:\n",
" df_estoque = pd.concat(df_list, ignore_index=True)\n",
"\n",
"df_estoque['PDV'] = df_estoque['PDV'].astype(str)\n",
"\n",
"df_estoque['SKU_FINAL'] = np.where(df_estoque['SKU_PARA'] == \"-\", df_estoque['SKU'], df_estoque['SKU_PARA'])\n",
"\n",
"df_estoque['SKU_FINAL']=df_estoque['SKU_FINAL'].astype(str)\n",
"\n",
"df_estoque = df_estoque[df_estoque['Arquivo_Origem']== \"BOT.csv\"]\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "db3b7495",
"metadata": {},
"outputs": [],
"source": [
"df_bi_vendas = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\VENDAS BI\\data (1).xlsx\")\n",
"\n",
"df_bi_vendas['Ciclo_ultimos2'] = df_bi_vendas['Ciclo'].str.rsplit('.', n=1).str[-1]\n",
"\n",
"df_bi_vendas['Ciclo_ano'] = df_bi_vendas['Ciclo'].str.rsplit('.', n=1).str[0]\n",
"\n",
"df_bi_vendas['Ciclo_ano'] = df_bi_vendas['Ciclo_ano'].str.replace(\"C\",\"\")\n",
"\n",
"df_bi_vendas['CICLO_FINAL'] = 'C20' + df_bi_vendas['Ciclo_ano'].astype(str) + df_bi_vendas['Ciclo_ultimos2'].astype(str)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "113a3032",
"metadata": {},
"outputs": [],
"source": [
"df_bi_vendas.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29504e7c",
"metadata": {},
"outputs": [],
"source": [
"df_pdv = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\PDV\\PDV_ATT.xlsx\")\n",
"\n",
"df_pdv_origi = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\PDV\\PDV_ATT.xlsx\")\n",
"\n",
"df_pdv = df_pdv.rename(columns={'DESCRIÇÃO':'DESCRIÇÃO PDV'})\n",
"\n",
"df_pdv = df_pdv.drop(columns=['REGIÃO', 'ESTADO','CIDADE','GESTÃO', 'status'])\n",
"\n",
"df_pdv['PDV'] = df_pdv['PDV DESC'].str.split(\"-\").str[0].str.strip()\n",
"\n",
"df_pdv['UF'] = np.where(df_pdv['UF'] == 'VDC','BA',df_pdv['UF'])\n",
"\n",
"#ignorando a PDV que ainda não está online\n",
"df_pdv = df_pdv[df_pdv['DESCRIÇÃO PDV'] != '23813-COMERCIO-HIB VALENTE']\n",
"\n",
"df_pdv = df_pdv[df_pdv['SUPERVISOR'] != \"Inativa\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7c7c8be1",
"metadata": {},
"outputs": [],
"source": [
"df_pdv['PDV'] = df_pdv['PDV'].fillna(0).astype('int64')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae39bc1e",
"metadata": {},
"outputs": [],
"source": [
"calendario = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\CICLO 9\\CALENDARIO_CICLO\\Ciclo_Expandido_com_Datas.xlsx\")\n",
"\n",
"calendario['Date'] = pd.to_datetime(calendario['Date'])\n",
"\n",
"# Get today (normalized to midnight)\n",
"today = pd.Timestamp(\"today\").normalize()\n",
"\n",
"calendario['NUM_CICLO'] = calendario['Ciclo'].str[-2:].astype(int)\n",
"\n",
"calendario['ANO_CICLO'] = calendario['Ciclo'].str[0:5]\n",
"\n",
"calendario = calendario[calendario['MARCA'] == \"BOTICARIO\"]\n",
"\n",
"calendario['CICLOMAIS2'] = calendario['ANO_CICLO'].astype(str) + (calendario['NUM_CICLO'].astype(int) + 3).astype(str).str.zfill(2) #<<< MUDAR O \"4\" (CICLO ATUAL + 4 PARA ACHAR O CICLO DA SUGESTÃO) EX: C202505 -> C202509\n",
"ciclo_mais2 = calendario[calendario['Date'].dt.normalize() == today]['CICLOMAIS2'].iloc[0]\n",
"\n",
"# Filter rows where date matches today\n",
"filtered_calendario = calendario[calendario['Ciclo'] == ciclo_mais2][:1]\n",
"\n",
"filtered_calendario['dias_ate_inicio'] = filtered_calendario['INICIO CICLO'].iloc[0] - today\n",
"\n",
"filtered_calendario['dias_ate_inicio'] = filtered_calendario['dias_ate_inicio'].dt.days.astype(int)\n",
"\n",
"filtered_calendario['match'] = 1\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5589e67c",
"metadata": {},
"outputs": [],
"source": [
"filtered_calendario"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5ac3914a",
"metadata": {},
"outputs": [],
"source": [
"df_tabela = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\TABELA_PEDIDO\\Pedidos Semanais Especiais - BOT - 202510 (2).xlsx\")\n",
"\n",
"df_tabela = df_tabela[df_tabela['Região'] == 'NNE'] \n",
"\n",
"df_tabela = df_tabela[(df_tabela['Canal'] != 'Ecomm') | (df_tabela['Canal'] != 'Ecomm | VD') | (df_tabela['Canal'] != 'Ecomm | Loja')] #perguntar se isso aqui é vdd\n",
"\n",
"df_tabela['Canal'] = np.where((df_tabela['Canal'] == \"Loja\") | (df_tabela['Canal'] == \"Todos\") | (df_tabela['Canal'] == \"Loja | VD\"),\"TODOS\",\"VD\")\n",
"\n",
"df_tabela = df_tabela[df_tabela['Tipo de promoção'].str.contains('Lançamentos', na=False)]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "af3d5a5c",
"metadata": {},
"outputs": [],
"source": [
"df_tabela['Tipo de promoção'].value_counts()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1a338b98",
"metadata": {},
"outputs": [],
"source": [
"df_similares = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\PRODUTO_SIMILAR\\PRODUTOS SIMILARES.xlsx\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39ddc830",
"metadata": {},
"outputs": [],
"source": [
"df_similares = pd.merge(left=df_similares,right=calendario[['Ciclo','INICIO CICLO','FIM CICLO','DURAÇÃO']], how= 'left', left_on = 'CICLO SIMILAR',right_on = 'Ciclo' )\n",
"\n",
"df_similares = df_similares.drop(columns=['INICIO DO CICLO SIMILAR','FIM DO CICLO SIMILAR', 'DURAÇÃO DO CICLO DO SIMILAR','Ciclo','DESCRIÇÃO SIMILAR'])\n",
"\n",
"df_similares = df_similares.rename(columns={'INICIO CICLO':'INICIO CICLO SIMILAR','FIM CICLO':'FIM CICLO SIMILAR','DURAÇÃO':'DURAÇÃO CICLO SIMILAR'})\n",
"df_similares.drop_duplicates(inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2eb0975",
"metadata": {},
"outputs": [],
"source": [
"df_draft = df_draft.rename(columns={'Descrição':'DESCRIÇÃO SIMILAR'})\n",
"\n",
"df_draft = df_draft.drop(columns=['Subcategoria', 'Lançamento', 'Desativação',\n",
" 'Dias sem venda',\n",
" 'Promoção Próximo Ciclo', 'Promoção Próximo Ciclo + 1','Compra inteligente semanal/Sugestão de compra',\n",
" 'Compra inteligente Próximo Ciclo',\n",
" 'Compra inteligente Próximo Ciclo + 1', 'Item Desativado',\n",
" 'Data Prevista Regularização', 'Carteira Bloqueada Para Novos Pedidos',\n",
" 'Planograma', 'Quantidade por caixa', 'Preço Sell In','Item analisado', 'Histórico de Vendas do Ciclo 202505'])\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2390c5b2",
"metadata": {},
"outputs": [],
"source": [
"df_draft['PROJEÇÃO DE VENDAS CICLO'] = df_draft['Projeção Próximo Ciclo + 1'] - df_draft['Projeção Próximo Ciclo']"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c6d00ef5",
"metadata": {},
"outputs": [],
"source": [
"df_venda_diaria = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BASE DE DADOS LANÇAMENTO\\BOT\\VENDAS_PRATICO\\VENDAS SIMI C10 - FormFiltroConsultaVendaSintetica_09_05_2025_11_30_54.xls\")\n",
"\n",
"df_venda_diaria.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a82629ba",
"metadata": {},
"outputs": [],
"source": [
"df_venda_diaria['PDV'] = df_venda_diaria['Unidade de Negócio'].str.split(\"-\").str[0].str.strip()\n",
"\n",
"df_venda_diaria['Dia'] = pd.to_datetime(df_venda_diaria['Dia'], format='%d/%m/%Y')\n",
"\n",
"df_venda_diaria = pd.merge(left=df_venda_diaria,right=calendario[['Ciclo','Date']],left_on='Dia',right_on='Date',how='inner')\n",
"\n",
"df_venda_diaria = df_venda_diaria.drop(columns='Date')\n",
"\n",
"df_venda_diaria.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4cd37229",
"metadata": {},
"outputs": [],
"source": [
"df_venda_diaria = df_venda_diaria.drop_duplicates()\n",
"\n",
"df_venda_diaria.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15773282",
"metadata": {},
"outputs": [],
"source": [
"df_venda_agrupado = df_venda_diaria.groupby(['PDV', 'Código do Produto','Ciclo'])['Quantidade'].sum().reset_index()\n",
"df_venda_agrupado"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6dad6151",
"metadata": {},
"outputs": [],
"source": [
"df_pdv['MATCH'] = 1\n",
"\n",
"df_similares['MATCH'] = 1\n",
"\n",
"df_similares = pd.merge(left=df_similares,right=df_pdv,right_on=['MATCH'],left_on=['MATCH'],how='inner')\n",
"\n",
"df_similares = df_similares.drop_duplicates()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2b33a11",
"metadata": {},
"outputs": [],
"source": [
"df_similares.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "63c52601",
"metadata": {},
"outputs": [],
"source": [
"df_final = pd.merge(left=df_similares,right=df_draft,right_on=['SKU','PDV'],left_on=['PRODUTO SIMILAR','PDV'],how='left')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "90a54c84",
"metadata": {},
"outputs": [],
"source": [
"df_final = pd.merge(left=df_final, right=filtered_calendario[['Ciclo','INICIO CICLO','FIM CICLO','DURAÇÃO','match','dias_ate_inicio']], on='match',how='left')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15b16b69",
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n",
"#df_final = pd.merge(left=df_final,right=df_pdv[['PDV', 'CANAL', 'DESCRIÇÃO PDV', 'PDV DESC','UF','ANALISTA','SUPERVISOR']],on = 'PDV',how='inner')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a453dc4",
"metadata": {},
"outputs": [],
"source": [
"df_bi_vendas = df_bi_vendas.rename(columns={'Quantidade':'Vendas Ciclo Lançamento'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a2a92cc7",
"metadata": {},
"outputs": [],
"source": [
"\n",
"df_bi_vendas['SKU2'] = df_bi_vendas['SKU2'].astype(str) \n",
"\n",
"df_final['PRODUTO SIMILAR'] = df_final['PRODUTO SIMILAR'].astype(str)\n",
"\n",
"df_bi_vendas['PDV'] = df_bi_vendas['PDV'].astype('Int64') \n",
"\n",
"df_final['SKU'] = df_final['SKU'].astype(str)\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_bi_vendas,right_on=['PDV','SKU2','CICLO_FINAL'],left_on=['PDV','PRODUTO SIMILAR','CICLO SIMILAR'],how='left')\n",
"df_final.shape "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2f11abcb",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "085cde87",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['SKU','match',\n",
" 'Ciclo_y',\n",
" 'SKU1', 'SKU2', 'Campanha','TOTAL PV',\n",
" 'Ciclo_ultimos2', 'Ciclo_ano', 'CICLO_FINAL'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "57d4871f",
"metadata": {},
"outputs": [],
"source": [
"df_final['CANAL'] = np.where((df_final['CANAL'] == 'LJ') | (df_final['CANAL'] == 'HIB'), \"TODOS\" , np.where((df_final['CANAL'] == 'CD') | (df_final['CANAL'] == 'VD'), \"VD\", df_final['CANAL']))\n",
"\n",
"df_final['CANAL'].value_counts()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e4e5868e",
"metadata": {},
"outputs": [],
"source": [
"df_tabela['Código'] = df_tabela['Código'].astype(str)\n",
"df_final['PRODUTO LANÇAMENTO'] = df_final['PRODUTO LANÇAMENTO'].astype(str)\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_tabela[['Canal', 'Código','Ação consumidor','IAF','Foco','Marca','Categoria',\n",
" 'Percentual de desconto consumidor', 'Ação revendedor',\n",
" 'Percentual de desconto revendedor','Tipo de promoção']],right_on=['Código'],left_on=['PRODUTO LANÇAMENTO'],how='left')\n",
"df_final.shape "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d6b65a39",
"metadata": {},
"outputs": [],
"source": [
"df_estoque = df_estoque.rename(columns={'SKU_FINAL':'SKU_PARA_VALIDACAO'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aaa90522",
"metadata": {},
"outputs": [],
"source": [
"df_estoque['PDV'] = df_estoque['PDV'].astype('int64')\n",
"\n",
"df_final = pd.merge( left= df_final, right = df_estoque[['SKU_PARA_VALIDACAO','Arquivo_Origem','PDV']], left_on= ['PRODUTO SIMILAR','PDV'], right_on=['SKU_PARA_VALIDACAO','PDV'], how='left')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94f1a76f",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=[\n",
"'SKU_PARA_VALIDACAO'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c3395775",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e5f7cefc",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns[35:41]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "efa6b757",
"metadata": {},
"outputs": [],
"source": [
"df_final['PDV_SKU'] = df_final['PDV'].astype(str) + df_final['PRODUTO SIMILAR'].astype(str) \n",
"\n",
"df_final['UFPRODUTO'] = df_final['UF'].astype(str) + df_final['PRODUTO SIMILAR'].astype(str)\n",
"\n",
"\n",
"VENDA_SIMILAR_6_MESES= df_final.columns[35:41]\n",
"\n",
"df_final['Pico Vendas Similar Ultimos 6 ciclos'] = df_final[VENDA_SIMILAR_6_MESES].max(axis=1)\n",
"\n",
"df_final = df_final.drop_duplicates()\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f10b3982",
"metadata": {},
"outputs": [],
"source": [
"df_venda_agrupado['PDV'] = df_venda_agrupado['PDV'].astype('int64')\n",
"\n",
"df_final['CICLO SIMILAR'] = df_final['CICLO SIMILAR'].astype(str)\n",
"\n",
"df_venda_agrupado['Código do Produto'] = df_venda_agrupado['Código do Produto'].astype(str)\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_venda_agrupado,right_on=['PDV','Código do Produto','Ciclo'],left_on=['PDV','PRODUTO SIMILAR','CICLO SIMILAR'],how='left')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f96e45b",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['Ciclo','Código do Produto','Vendas Ciclo Lançamento'])\n",
"\n",
"df_final = df_final.rename(columns={'Quantidade':'Vendas Ciclo Lançamento'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5801d05b",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns[25:41]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41c64323",
"metadata": {},
"outputs": [],
"source": [
"# Suponha que os meses estão nas colunas 10 a 26 (17 colunas = 17 meses)\n",
"colunas_mensais = df_final.columns[25:41]\n",
"\n",
"# Passo 1: Soma todas as linhas (itens) por mês → resultado: total por mês\n",
"soma_mensal = df_final[colunas_mensais].sum()\n",
"\n",
"# Passo 2: Calcula a variação percentual de um mês para o outro\n",
"variacao_mensal = soma_mensal.pct_change()\n",
"variacao_mensal = variacao_mensal.dropna()\n",
"\n",
"variacao_mensal = variacao_mensal[np.isfinite(variacao_mensal)]\n",
"\n",
"# Passo 3: Calcula a média da variação (ignorando o primeiro NaN)\n",
"media_variacao = variacao_mensal[1:].mean()\n",
"\n",
"# Calcula média e desvio padrão\n",
"media = variacao_mensal.mean()\n",
"desvio = variacao_mensal.std()\n",
"\n",
"# Define limite (ex: 2 desvios padrão)\n",
"limite_superior = media + 2 * desvio\n",
"limite_inferior = media - 2 * desvio\n",
"\n",
"# Filtra dados dentro do limite\n",
"filtro = variacao_mensal.between(limite_inferior, limite_superior)\n",
"df_filtrado = variacao_mensal[filtro]\n",
"CRESCIMENTO = round(df_filtrado.mean(),4)\n",
"\n",
"df_final['CRESCIMENTO'] = CRESCIMENTO\n",
"\n",
"CRESCIMENTO\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "02565655",
"metadata": {},
"outputs": [],
"source": [
"variacao_mensal.info"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "137f5531",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns[27:28]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3c027cfc",
"metadata": {},
"outputs": [],
"source": [
"venda_similar_mesmo_ciclo_ano_passado = df_final.columns[27:28] #<<<<<<< CICLO ATUAL É [37:38]\n",
"ciclo_ano_passado = df_final.columns[27:28].str.split(\" \")[0][-1]\n",
"df_final[ciclo_ano_passado] = df_final[venda_similar_mesmo_ciclo_ano_passado]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "28f74b58",
"metadata": {},
"outputs": [],
"source": [
"df_final['Vendas Ciclo Lançamento'] = df_final['Vendas Ciclo Lançamento'].fillna(0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "58642d77",
"metadata": {},
"outputs": [],
"source": [
"vendas_todos_historicos = df_final.columns[25:41]\n",
"\n",
"df_final['MEDIANA DO HISTÓRICO'] = df_final[vendas_todos_historicos].dropna().median(axis=1)\n",
"\n",
"df_final['MEDIA DO HISTÓRICO'] = df_final[vendas_todos_historicos].dropna().mean(axis=1)\n",
"\n",
"df_final['MEDIANA DO HISTÓRICO'] = np.where(df_final['MEDIANA DO HISTÓRICO'] > 0, df_final['MEDIANA DO HISTÓRICO'], df_final['MEDIA DO HISTÓRICO'] )#validar se foi\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "69473155",
"metadata": {},
"outputs": [],
"source": [
"crescimento = df_final['CRESCIMENTO']\n",
"vendas_lanc = df_final['Vendas Ciclo Lançamento']\n",
"pico_similar = df_final['Pico Vendas Similar Ultimos 6 ciclos']\n",
"mediana_hist = df_final['MEDIANA DO HISTÓRICO']\n",
"\n",
"# Primeiro cálculo intermediário\n",
"df_final['PV GINSENG'] = np.where(df_final['CRESCIMENTO'] * df_final[ciclo_ano_passado] + df_final[ciclo_ano_passado] < df_final['MEDIANA DO HISTÓRICO'],\n",
" round(df_final['CRESCIMENTO'] * df_final['MEDIANA DO HISTÓRICO']+ df_final['MEDIANA DO HISTÓRICO'],0), \n",
" round(df_final['CRESCIMENTO']*df_final[ciclo_ano_passado]+df_final[ciclo_ano_passado],0))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d29a3365",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns[25:38]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3cf3efe7",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.rename(columns={df_final.columns[38]: \"C-4\", df_final.columns[39]: \"C-3\",df_final.columns[40]: \"C-2\",df_final.columns[41]: \"C-1\"})\n",
"\n",
"df_final.drop(columns=df_final.columns[25:38], inplace=True)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "303291c9",
"metadata": {},
"outputs": [],
"source": [
"df_final.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b8b3551",
"metadata": {},
"outputs": [],
"source": [
"\n",
"marca_promo = df_estoque['Arquivo_Origem'].iloc[0].replace('.csv','')\n",
"\n",
"df_final['INICIO CICLO'] = pd.to_datetime(df_final['INICIO CICLO'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"df_final['FIM CICLO'] = pd.to_datetime(df_final['FIM CICLO'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"df_final['INICIO CICLO SIMILAR'] = pd.to_datetime(df_final['INICIO CICLO SIMILAR'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"df_final['FIM CICLO SIMILAR'] = pd.to_datetime(df_final['FIM CICLO SIMILAR'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"\n",
"\n",
"df_final = df_final.rename(columns={'Ciclo_x': 'Ciclo'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3900ec24",
"metadata": {},
"outputs": [],
"source": [
"df_final = pd.merge(left=df_final,right=df_pdv_origi[['PDV','CANAL','UF']],how='inner',on='PDV')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f8ba376a",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['CANAL_x','UF_x','Categoria_y'])\n",
"\n",
"df_final = df_final.rename(columns={'CANAL_y':'CANAL', 'UF_y':'UF','MARCA_x':'MARCA','Categoria_x':'Categoria'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7d904672",
"metadata": {},
"outputs": [],
"source": [
"# Columns to bring up front\n",
"priority_cols = [\n",
" 'Ciclo','INICIO CICLO','FIM CICLO','ANALISTA','SUPERVISOR','UF','CANAL','PDV', 'DESCRIÇÃO PDV','DURAÇÃO',\t\n",
" 'Classe','PRODUTO LANÇAMENTO','DESCRIÇÃO DO LANÇAMENTO','MARCA','Foco',\n",
" 'PRODUTO SIMILAR','DESCRIÇÃO SIMILAR','CICLO SIMILAR','INICIO CICLO SIMILAR','FIM CICLO SIMILAR','DURAÇÃO CICLO SIMILAR',\n",
" 'Ação consumidor',\t'Percentual de desconto consumidor','Ação revendedor','Percentual de desconto revendedor','Estoque Atual',\n",
" 'Estoque em Transito',\t'Pedido Pendente','DESCRIÇÃO SIMILAR', 'Histórico de Vendas do Ciclo Atual',\n",
"\t'C-4',\t'C-3',\t'C-2',\t'C-1'\n",
"]\n",
"\n",
"# All remaining columns\n",
"other_cols = [col for col in df_final.columns if col not in priority_cols]\n",
"\n",
"# Reorder\n",
"df_final = df_final[priority_cols + other_cols]\n",
"\n",
"df_final['SUGESTÃO ABTASTECIMENTO'] = ''\n",
"\n",
"df_final['SUGESTÃO COMERCIAL'] = ''\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "43f96709",
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['Marca','CRESCIMENTO','Canal','Código','Tipo de promoção','dias_ate_inicio','PDV DESC','UFPRODUTO','Arquivo_Origem','UFPRODUTO',\n",
" 'PDV_SKU','MEDIANA DO HISTÓRICO','MEDIA DO HISTÓRICO'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23d6fe59",
"metadata": {},
"outputs": [],
"source": [
"df_final['chave'] = df_final['PDV'].astype(str) + df_final['PRODUTO LANÇAMENTO'].astype(str)\n",
"\n",
"chaves_duplicadas = (\n",
" df_final.groupby('chave')['Percentual de desconto consumidor']\n",
" .count()\n",
" .loc[lambda x: x == 2]\n",
" .index\n",
")\n",
"\n",
"# Selecionar essas linhas\n",
"duplicadas = df_final[df_final['chave'].isin(chaves_duplicadas)]\n",
"\n",
"# Filtrar apenas os grupos onde pelo menos uma linha tem 0.0\n",
"grupos_com_zero = duplicadas.groupby('chave').filter(\n",
" lambda g: (g['Percentual de desconto consumidor'] == \"0,00\").any()\n",
")\n",
"\n",
"# Remover apenas as linhas com 0.0 dessas chaves\n",
"limpos = grupos_com_zero[grupos_com_zero['Percentual de desconto consumidor'] != \"0,00\"]\n",
"\n",
"# Concatenar com o restante do dataframe que não foi afetado\n",
"resto = df_final[~df_final['chave'].isin(grupos_com_zero['chave'])]\n",
"df_final = pd.concat([resto, limpos], ignore_index=True)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "08faefd9",
"metadata": {},
"outputs": [],
"source": [
"\n",
"from openpyxl import load_workbook\n",
"from openpyxl.styles import PatternFill, Font\n",
"\n",
"\n",
"# Export to Excel\n",
"output_file = f'C:\\\\Users\\\\joao.herculano\\\\Documents\\\\Lançamento!!!_{marca_promo}_{ciclo_mais2}_20.05!!.xlsx'\n",
"with pd.ExcelWriter(output_file, engine='openpyxl') as writer:\n",
" df_final.to_excel(writer, index=False, sheet_name='Sheet1')\n",
"\n",
"# Apply styles\n",
"wb = load_workbook(output_file)\n",
"ws = wb['Sheet1']\n",
"\n",
"# Style header\n",
"header_fill = PatternFill(start_color='ADD8E6', end_color='ADD8E6', fill_type='solid') # Light Blue\n",
"header_font = Font(color='FFFFFF', bold=True) # White & Bold\n",
"\n",
"for cell in ws[1]:\n",
" cell.fill = header_fill\n",
" cell.font = header_font\n",
"\n",
"# Style rows: gray/white alternating\n",
"gray_fill = PatternFill(start_color='DDDDDD', end_color='DDDDDD', fill_type='solid') # Light gray\n",
"\n",
"for i, row in enumerate(ws.iter_rows(min_row=2, max_row=ws.max_row), start=2):\n",
" if i % 2 == 0:\n",
" for cell in row:\n",
" cell.fill = gray_fill\n",
"\n",
"# Save styled workbook\n",
"wb.save(output_file)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f039df31",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,155 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "fd67cc1a",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"c:\\Users\\joao.herculano\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\openpyxl\\worksheet\\_reader.py:329: UserWarning: Unknown extension is not supported and will be removed\n",
" warn(msg)\n",
"c:\\Users\\joao.herculano\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\openpyxl\\worksheet\\_reader.py:329: UserWarning: Unknown extension is not supported and will be removed\n",
" warn(msg)\n",
"c:\\Users\\joao.herculano\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\openpyxl\\worksheet\\_reader.py:329: UserWarning: Unknown extension is not supported and will be removed\n",
" warn(msg)\n",
"c:\\Users\\joao.herculano\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\openpyxl\\worksheet\\_reader.py:329: UserWarning: Unknown extension is not supported and will be removed\n",
" warn(msg)\n"
]
}
],
"source": [
"import os\n",
"import glob\n",
"import pandas as pd\n",
"\n",
"# Directory path\n",
"folder_path = r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BOT\\Bot - C13\\LANÇAMENTOS\\devolutiva comercial\"\n",
"# Collect files\n",
"file_paths = glob.glob(os.path.join(folder_path, \"*.xls\")) + glob.glob(os.path.join(folder_path, \"*.xlsx\"))\n",
"\n",
"# Required columns\n",
"required_columns = [\"PDV\", \"PRODUTO LANÇAMENTO\", \"SUGESTÃO COMERCIAL\"]\n",
"\n",
"# Load files\n",
"dfs = []\n",
"for file_path in file_paths:\n",
" try:\n",
" df = pd.read_excel(file_path,sheet_name='Sheet1')\n",
" \n",
" missing = [col for col in required_columns if col not in df.columns]\n",
" \n",
" if missing:\n",
" print(f\"Missing columns {missing} ins file: {file_path}\")\n",
" continue # Skip file with missing columns\n",
"\n",
" df[\"source_file\"] = os.path.basename(file_path)\n",
" dfs.append(df)\n",
"\n",
" except Exception as e:\n",
" print(f\"Failed to read {file_path}: {e}\")\n",
"\n",
"# Combine\n",
"if dfs:\n",
" combined_df = pd.concat(dfs, ignore_index=True)\n",
"else:\n",
" print(\"No valid files loaded.\")\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "c4c50096",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"np.int64(82418)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\n",
"\n",
"combined_df['SUGESTÃO COMERCIAL'].isna().sum()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "3e1ada65",
"metadata": {},
"outputs": [],
"source": [
"combined_df = combined_df.drop_duplicates()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f5968d9a",
"metadata": {},
"outputs": [],
"source": [
"combined_df['chavers'] = combined_df['PDV'].astype('str') + combined_df['PRODUTO LANÇAMENTO'].astype('str')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "fd6a08e7",
"metadata": {},
"outputs": [],
"source": [
"combined_df['chavers'] = combined_df['chavers'].str.replace('.','')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "b6eee60e",
"metadata": {},
"outputs": [],
"source": [
"combined_df.to_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\BD_LANÇAMENTOS\\BOT\\Bot - C13\\LANÇAMENTOS\\compilado_comercial_BOTI!!!.xlsx\",index=False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "84f989f7",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -0,0 +1,51 @@
import pandas as pd
import numpy as np
import os
from datetime import date
def unificador_estoque(pasta_entrada):
hoje = date.today().isoformat()
caminho_saida = os.path.join(pasta_entrada, f"compilado_estoque_{hoje}.xlsx")
print("Salvando em:", caminho_saida)
subpastas = [
os.path.join(pasta_entrada, d)
for d in os.listdir(pasta_entrada)
if os.path.isdir(os.path.join(pasta_entrada, d))
]
df_list = []
for subpasta in subpastas:
arquivos = [f for f in os.listdir(subpasta) if f.endswith(".csv")]
nome_pasta = os.path.basename(subpasta)
for arquivo in arquivos:
caminho_arquivo = os.path.join(subpasta, arquivo)
try:
df = pd.read_csv(caminho_arquivo, encoding="utf-8", low_memory=False)
df["Arquivo_Origem"] = arquivo
df["Pasta_Origem"] = nome_pasta
df_list.append(df)
except Exception as e:
print(f"Erro ao ler o arquivo {arquivo}: {e}")
if not df_list:
raise ValueError("Nenhum arquivo CSV válido foi encontrado.")
df_estoque = pd.concat(df_list, ignore_index=True)
df_estoque["PDV"] = df_estoque["PDV"].astype(str)
df_estoque["SKU_FINAL"] = np.where(
df_estoque["SKU_PARA"] == "-",
df_estoque["SKU"],
df_estoque["SKU_PARA"]
).astype(str)
try:
df_estoque.to_excel(caminho_saida, index=False)
except Exception as e:
raise RuntimeError(f"Erro ao salvar o arquivo Excel: {e}")
return caminho_saida

View File

@ -0,0 +1,71 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "eba7e63d",
"metadata": {},
"outputs": [],
"source": [
"from compilador_estoque import unificador_estoque\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "b59cf803",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Salvando em: C:/Users/joao.herculano/OneDrive - GRUPO GINSENG/Documentos/estoque EUD 14.05\\compilado_estoque_2025-05-14.xlsx\n"
]
},
{
"data": {
"text/plain": [
"'C:/Users/joao.herculano/OneDrive - GRUPO GINSENG/Documentos/estoque EUD 14.05\\\\compilado_estoque_2025-05-14.xlsx'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"unificador_estoque('C:/Users/joao.herculano/OneDrive - GRUPO GINSENG/Documentos/estoque EUD 14.05')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7b91d6db",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -0,0 +1,67 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 4,
"id": "967a68c6",
"metadata": {},
"outputs": [],
"source": [
"from datetime import date"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "04e89b60",
"metadata": {},
"outputs": [],
"source": [
"with open(r\"C:\\Users\\joao.herculano\\OneDrive - GRUPO GINSENG\\Ambiente de Trabalho\\acompanhamento improdutivo.csv\",mode='a',newline='',encoding='utf8') as f:\n",
" f.write('DATA;TOTAL_IMPRODUTIVO\\n')"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "7ef5065f",
"metadata": {},
"outputs": [],
"source": [
"hoje = date.today()"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "93c54816",
"metadata": {},
"outputs": [],
"source": [
"with open(r\"C:\\Users\\joao.herculano\\OneDrive - GRUPO GINSENG\\Ambiente de Trabalho\\acompanhamento improdutivo.csv\",mode='a',newline='',encoding='utf8') as f:\n",
" f.write(f'{hoje};2.931.906,29')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

View File

@ -11,10 +11,10 @@ from email.message import EmailMessage
from email.utils import make_msgid
from pathlib import Path
from datetime import datetime, time
from email.mime.image import MIMEImage
import warnings
warnings.filterwarnings("ignore", message="pandas only supports SQLAlchemy")
hoje = datetime.today().strftime("%d/%m/%Y")
@ -40,7 +40,7 @@ calendario['ciclomais2'] = calendario['ano_ciclo'].astype(str) + (calendario['nu
ciclo_mais2 = calendario[calendario['date'].dt.normalize() == today]['ciclomais2'].iloc[0]
filtered_calendario = calendario[calendario['ciclo'] == ciclo_mais2][:1].copy()
filtered_calendario['dias_ate_fim'] = (filtered_calendario['fim ciclo'].iloc[0] - today).days
print(filtered_calendario[['duração', 'dias_ate_fim']])
#print(filtered_calendario[['duração', 'dias_ate_fim']])
query = '''
SELECT
@ -71,7 +71,7 @@ df.columns = df.columns.str.lower()
filtered_calendario.columns = filtered_calendario.columns.str.lower()
df['ddv'] = df['pv_mar'] / filtered_calendario['duração'].values[0]
df['estoque_seguranca'] = np.ceil((df['media_vendas']/20)*11 - (df['ddv']*11)).astype(int) #media de vendas realizada+projetada
df['estoque_seguranca'] = np.ceil((df['media_vendas']/20)*14 - (df['ddv']*14)).astype(int) #media de vendas realizada+projetada
df['estoque_seguranca'] = np.where(df['estoque_seguranca'] <1,1,df['estoque_seguranca'])
df['risco_ruptura'] = np.where(df['estoque_seguranca'] > df['estoque'], "SIM", "NÃO")
df['quantidade_ruptura'] = df['estoque_seguranca'] - df['estoque']
@ -84,7 +84,7 @@ assunto = config['email_ruptura']['assunto']
df_rpt = pd.read_excel(r"C:\Users\joao.herculano\Downloads\Ruptura Cliente CP GINSENG - 09.06.xlsx")
df_rpt.columns = df_rpt.columns.str.lower()
print(df_rpt.columns)
df['pdv'] = df['pdv'].astype('Int64')
df['sku'] = df['sku'].astype('Int64')
@ -109,7 +109,7 @@ df2 = df2.join(pdvs_maior_excesso, on=['uf', 'sku'])
df2['maior excesso na uf'] = df2['maior_excesso_por_uf'].apply(lambda x: 'não tem excesso no uf' if x == 0 else None)
df2['maior excesso na uf'] = df2['maior excesso na uf'].combine_first(df2['pdv_maior_excesso'])
df2['quantidade_ruptura'] = df2['quantidade_ruptura'].clip(lower=0)
print(df2[['uf', 'sku', 'excesso', 'maior_excesso_por_uf', 'maior excesso na uf']].head())
df2.drop(columns=['pdv_maior_excesso','sku1'], inplace=True)
df2['estoque livre?'] = np.where(
@ -185,7 +185,7 @@ de_effi['data'] = pd.to_datetime(de_effi['data'], errors='coerce')
grouped = (
de_effi.groupby('data')['quantidade_ruptura']
.sum()
.sort_index()
.sort_index().tail(30)
)
# Step 3: Plot
@ -218,14 +218,14 @@ plt.close()
with pd.ExcelWriter(excel_path, engine='openpyxl') as writer:
df2.to_excel(writer, sheet_name='Detalhado', index=False)
df3.to_excel(writer, sheet_name='Resumo', index=False)
print(excel_path)
ruptura_total = df2['quantidade_ruptura'].sum()
ruptura_por_uf_pct = (
df2.groupby('uf')['quantidade_ruptura'].sum()
.sort_values(ascending=True)
.apply(lambda x: (x / ruptura_total) * 100)
)
print(ruptura_por_uf_pct)
#print(ruptura_por_uf_pct)
ax = ruptura_por_uf_pct.plot(kind='barh', figsize=(10, 6), color='skyblue')
for i, v in enumerate(ruptura_por_uf_pct):
ax.text(v + 0.3, i, f"{v:.1f}%", va='center')
@ -254,6 +254,7 @@ html_email = f"""
<body>
<p>{boa}</p>
<p>Compartilhamos o relatório de ruptura projetada, com o objetivo de monitorar os itens com maior risco de ruptura nos próximos dias.</p>
<p><strong>Atualizamos o relatório, e agora mandaremos diariamente às 10:00 automaticamente. Pedimos paciência nessa etapa e contamos com o feedback de vocês.</strong></p>
<p>O relatório a seguir apresenta as seguintes informações:</p>
<ul>
<li>Estoque atual;</li>
@ -294,4 +295,5 @@ with smtplib.SMTP('smtp-mail.outlook.com', 587) as smtp:
smtp.login(remetente, senha)
smtp.send_message(msg)
print("E-mail enviado com sucesso.")
print("E-mail enviado com sucesso.",hoje)
print("############################################################")

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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.")

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,18 @@
[credenciais]
remetente=joao.herculano@grupoginseng.com.br
senha=Cecigaming@21
[email]
assunto = ACOMPANHAMENTO IMPRODUTIVOS
destinatarios=lucas.Barbosa@grupoginseng.com.br,Andressa.Rocha@grupoginseng.com.br,Lais.Santos@grupoginseng.com.br,Daniel.Rodrigues@grupoginseng.com.br,Darlin.Cunha@grupoginseng.com.br,Dielly.Gomes@grupoginseng.com.br,Haryadne.Gomes@grupoginseng.com.br,Lucas.Bento@grupoginseng.com.br,Marcyara.Batista@grupoginseng.com.br,Pedro.Horgos@grupoginseng.com.br,Thayllan.Santos@grupoginseng.com.br,Jefferson.Ferreira@grupoginseng.com.br,Luan.Omena@grupoginseng.com.br,vinicius.souza@grupoginseng.com.br
[email_ruptura]
assunto = ACOMPANHAMENTO DE RUPTURA PROJETADA
destinatarios=Lucas.Barbosa@grupoginseng.com.br,Andressa.Rocha@grupoginseng.com.br,Lais.Santos@grupoginseng.com.br,Daniel.Rodrigues@grupoginseng.com.br,Darlin.Cunha@grupoginseng.com.br,Dielly.Gomes@grupoginseng.com.br,Haryadne.Gomes@grupoginseng.com.br,Lucas.Bento@grupoginseng.com.br,Marcyara.Batista@grupoginseng.com.br,Pedro.Horgos@grupoginseng.com.br,Thayllan.Santos@grupoginseng.com.br,Jefferson.Ferreira@grupoginseng.com.br,Luan.Omena@grupoginseng.com.br,vinicius.souza@grupoginseng.com.br
[banco]
host = 10.77.77.10
user = hubsupply
password = =c6#94sE&(v2

View File

@ -6,6 +6,7 @@ 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
@ -16,7 +17,7 @@ from datetime import datetime, time
config = configparser.ConfigParser()
config.read(r"C:\Users\joao.herculano\Documents\Enviador de email\credenciais.ini")
config.read(r"relatório_improdutivo\credenciais.ini")
print(config['banco']['host'],config['banco']['user'],config['banco']['password'])
@ -57,7 +58,9 @@ assunto = config['email']['assunto']
print(remetente,senha,destinatarios,assunto)
pdvs = pd.read_excel(r"C:\Users\joao.herculano\Documents\PDV_ATT.xlsx")
pdvs = pd.read_excel(r"relatório_improdutivo\PDV_ATT.xlsx")
df['loja_id'] = df['loja_id'].astype('Int64')
pdvs['PDV'] = pdvs['PDV'].astype('Int64')
@ -108,22 +111,45 @@ excel_path = Path("relatorio.xlsx")
df2.to_excel(excel_path, index=False)
# 2. Criar e salvar gráfico
# Gerar gráfico melhorado - Estoque parado por UF
plot_df = df2.groupby('UF')['valor_estoque_parado'].sum().reset_index()
plt.figure(figsize=(6, 4))
ax = sns.barplot(data=plot_df, x='UF', y='valor_estoque_parado', errorbar=None)
sns.set_theme(style="whitegrid")
plt.figure(figsize=(12, 7))
ax = sns.barplot(
data=plot_df,
x='UF',
y='valor_estoque_parado',
palette='crest',
errorbar=None
)
ax.yaxis.set_major_formatter(mtick.StrMethodFormatter('R${x:,.2f}'))
# Anotar valores em cima das barras
for p in ax.patches:
valor = p.get_height()
ax.annotate(f'R$ {valor:,.2f}', (p.get_x() + p.get_width() / 2, valor),
ha='center', va='bottom', fontsize=9)
plt.title("Estoque parado por UF")
plt.ylabel("Valor em Reais")
plt.xlabel("UF")
ax.annotate(
f'R$ {valor:,.2f}',
(p.get_x() + p.get_width() / 2, valor),
ha='center', va='bottom',
fontsize=10,
fontweight='bold'
)
plt.title("Estoque Parado por UF", fontsize=18, fontweight='bold')
plt.ylabel("Valor em Reais", fontsize=13)
plt.xlabel("UF", fontsize=13)
plt.xticks(fontsize=11)
plt.yticks(fontsize=11)
sns.despine()
plt.tight_layout()
plt.savefig("grafico.png")
plt.close()
# Obtém a hora atual
agora = datetime.now().time()
hoje = datetime.today().strftime("%d/%m/%Y")
@ -147,7 +173,7 @@ df2['DATA'] = hoje
df3 = df2.groupby('DATA', as_index=False)['valor_estoque_parado'].sum()
path2 = r'C:\Users\joao.herculano\OneDrive - GRUPO GINSENG\Documentos\acompanhamentos\40D sem Venda\acompanhamento40DSV.xlsx'
path2 = r'relatório_improdutivo\acompanhamento40DSV.xlsx'
# Tenta abrir e escrever com append
with pd.ExcelWriter(path2, mode='a', engine='openpyxl', if_sheet_exists='overlay') as writer:
@ -159,8 +185,47 @@ with pd.ExcelWriter(path2, mode='a', engine='openpyxl', if_sheet_exists='overlay
# Escreve sem cabeçalho se não for a primeira linha
df3.to_excel(writer, index=False, header=not start_row > 1, startrow=start_row)
de_effi = pd.read_excel(r'relatório_improdutivo\acompanhamento40DSV.xlsx')
de_effi['Data'] = pd.to_datetime(de_effi['Data'], errors='coerce')
# Step 2: Group and sort
grouped = (
de_effi.groupby('Data')['Valor']
.sum()
.sort_index()
)
# Step 3: Plot
plt.figure(figsize=(12, 6))
plt.plot(grouped.index, grouped.values, marker='o', linestyle='-', color='cornflowerblue', linewidth=2)
# Step 4: Format numbers with dot ('.') separator, no decimals
for x, y in zip(grouped.index, grouped.values):
label = f"{y:,.0f}".replace(",", ".") # format like 75.063
plt.text(x, y + max(grouped.values) * 0.015, label, ha='center', fontsize=9)
# Step 5: Format chart
plt.title('Evolução de Estoque Improdutivo por Data', fontsize=14)
plt.xlabel('Data', fontsize=8)
plt.ylabel('Estoque Improdutivo', fontsize=12)
plt.grid(True, linestyle='--', alpha=0.6)
# ✅ Set xticks to match the actual data points
ax = plt.gca()
ax.set_xticks(grouped.index)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d/%m/%Y'))
plt.xticks(rotation=45)
# Format x-axis as dd/mm/yyyy
plt.gca().set_xticklabels([d.strftime('%d/%m/%Y') for d in grouped.index])
plt.tight_layout()
plt.savefig("grafico2.png")
plt.close()
# 3. Criar e-mail com imagem embutida
grafico_cid = make_msgid()[1:-1] # remove < >
grafico2_cid = make_msgid()[1:-1]
msg = EmailMessage()
msg['From'] = remetente
msg['To'] = ', '.join(destinatarios)
@ -175,7 +240,7 @@ html_email = f"""
<p>
Segue o relatório semanal de estoque improdutivo referente às regiões de
Alagoas (AL), Bahia (BA), Sergipe (SE), Vitória da Conquista (VDC) e Iracê.
Alagoas (AL), Bahia (BA), Sergipe (SE), Vitória da Conquista (VDC), Jacobina e Iracê.
</p>
<p>
@ -200,7 +265,8 @@ html_email = f"""
</p>
<p><b>Segue resumo:</b></p>
<img src="cid:{grafico_cid}">
<p><img src="cid:{grafico_cid}"></p>
<p><img src="cid:{grafico2_cid}"></p>
</body>
</html>
"""
@ -213,6 +279,9 @@ msg.add_alternative(html_email, subtype='html')
with open("grafico.png", 'rb') as img:
msg.get_payload()[1].add_related(img.read(), 'image', 'png', cid=grafico_cid)
with open("grafico2.png", 'rb') as img2:
msg.get_payload()[1].add_related(img2.read(), 'image', 'png', cid=grafico2_cid)
# 5. Anexar o arquivo Excel
with open(excel_path, 'rb') as f: