{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np \n",
"import glob\n",
"import os \n",
"from openpyxl import load_workbook\n",
"from openpyxl.styles import PatternFill, Font\n",
"from datetime import datetime"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"hoje = datetime.today().strftime('%Y-%m-%d')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# O QUE PRECISA PRA RODAR ESSE CÓDIGO:\n",
"\n",
"# Arquivo Draft\n",
"# Arquivo Estoque\n",
"# Arquivo BI preço\n",
"# Arquivo pdv\n",
"# Arquivo Calendario\n",
"# Arquivo tabela de compra\n",
"\n",
"#Atualizar o nome da marca no filtro do estoque."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"df_tabela = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\DB_PROMOÇÕES\\BOTICARIO\\C10\\TABELA DE PEDIDOS\\Pedidos Semanais Especiais - BOT - 202510.xlsx\")\n",
"\n",
"df_tabela = df_tabela[df_tabela['Ação revendedor'].notna() | df_tabela['Ação consumidor'].notna()]\n",
"\n",
"df_tabela = df_tabela[df_tabela['Região'] == 'NNE'] \n",
"\n",
"df_tabela = df_tabela[(df_tabela['Canal'] != 'Ecomm')]\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['Categoria'] != \"EMBALAGENS\") | (df_tabela['Categoria'] != \"SUPORTE À VENDA\")]\n",
"\n",
"df_tabela = df_tabela[df_tabela['Tipo de pedido'] == 'Semanal']\n",
"\n",
"df_tabela = df_tabela[~df_tabela['Descrição'].str.contains('PRM')]\n",
"\n",
"df_tabela = df_tabela[df_tabela['Tipo de produto']!= 'EDICAO LIMITADA']\n",
"\n",
"df_tabela['Ação revendedor'] = np.where(df_tabela['Ação revendedor'].isna(),df_tabela['Ação consumidor'],df_tabela['Ação revendedor'])\n",
"\n",
"df_tabela['Percentual de desconto revendedor'] = np.where(df_tabela['Percentual de desconto revendedor'].isna(),df_tabela['Percentual de desconto consumidor'],df_tabela['Percentual de desconto revendedor'])\n",
"\n",
"df_tabela['MATCH'] = 1\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Ciclo', 'Região', 'Canal', 'Código', 'Descrição', 'IAF',\n",
" 'Tipo de pedido', 'Foco', 'Unidade de negócio', 'Marca', 'Categoria',\n",
" 'Subcategoria', 'Quantidade por caixa', 'Tipo de promoção', 'Catálogo',\n",
" 'Tipo de produto', 'Ação consumidor',\n",
" 'Percentual de desconto consumidor', 'Ação revendedor',\n",
" 'Percentual de desconto revendedor', 'Sortimento P', 'Sortimento M',\n",
" 'Sortimento G', 'MATCH'],\n",
" dtype='object')"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_tabela.columns"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(702, 24)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_tabela.shape"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"df_pdv = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\DB_PROMOÇÕES\\BOTICARIO\\C09\\arquivos pra gerar\\pdvs\\PDV_ATT.xlsx\")\n",
"\n",
"df_pdv_origi = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\DB_PROMOÇÕES\\BOTICARIO\\C09\\arquivos pra gerar\\pdvs\\PDV_ATT.xlsx\")\n",
"\n",
"df_pdv = df_pdv.rename(columns={'DESCRIÇÃO':'DESCRIÇÃO PDV'})\n",
"\n",
"df_pdv = df_pdv[df_pdv['STATUS']!=\"INATIVO\"]\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 = df_pdv[df_pdv['CANAL']!='MTZ']\n",
"\n",
"#df_pdv['CANAL'] = np.where((df_pdv['CANAL']=='LJ')|(df_pdv['CANAL']=='HIB')|(df_pdv['CANAL']=='CD'),'TODOS','VD')\n",
"\n",
"df_pdv['MATCH'] = 1\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"df_pdv = df_pdv.drop(columns=['pdv como texto','PDV DESC'])"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_37488\\4129764549.py:10: DtypeWarning: Columns (7) have mixed types. Specify dtype option on import or set low_memory=False.\n",
" df_draft = pd.concat([pd.read_csv(file) for file in csv_files], ignore_index=True)\n"
]
},
{
"data": {
"text/plain": [
"(114430, 46)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"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\\BOT\\BOT - C11\\atualização\\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.shape\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"df_draft = df_draft.drop(columns=['Descrição','Compra inteligente semanal/Sugestão de compra',\n",
" 'Compra inteligente Próximo Ciclo',\n",
" 'Compra inteligente Próximo Ciclo + 1','Planograma', 'Quantidade por caixa', 'Preço Sell In', 'Quantidade',\n",
" 'Item analisado', 'Subcategoria',\n",
" 'Lançamento', 'Desativação',\n",
" 'Promoção Próximo Ciclo', 'Categoria'])"
]
},
{
"cell_type": "code",
"execution_count": 11,
"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\\BOT\\BOT - C11\\atualização\\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"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Ciclo', 'Região', 'Canal', 'Código', 'Descrição', 'IAF',\n",
" 'Tipo de pedido', 'Foco', 'Unidade de negócio', 'Marca', 'Categoria',\n",
" 'Subcategoria', 'Quantidade por caixa', 'Tipo de promoção', 'Catálogo',\n",
" 'Tipo de produto', 'Ação consumidor',\n",
" 'Percentual de desconto consumidor', 'Ação revendedor',\n",
" 'Percentual de desconto revendedor', 'Sortimento P', 'Sortimento M',\n",
" 'Sortimento G', 'MATCH'],\n",
" dtype='object')"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_tabela.columns"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"df_tabela = pd.merge(left=df_tabela,right=df_estoque[['SKU','SKU_FINAL']],left_on='Código',right_on='SKU',how='inner')\n",
"\n",
"df_tabela['Código'] = df_tabela['SKU_FINAL']\n",
"\n",
"df_tabela = df_tabela.drop(columns=['SKU','SKU_FINAL'])\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"df_estoque = df_estoque.drop(columns=['DESCRICAO', 'CATEGORIA', 'CLASSE', 'FASES PRODUTO',\n",
" 'LANCAMENTO', 'DESATIVACAO','COBERTURA ALVO',\n",
" 'ESTOQUE DE SEGURANCA','COBERTURA PROJETADA', \n",
" 'Pasta_Origem'])"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" SKU | \n",
" SKU_PARA | \n",
" PDV | \n",
" ESTOQUE ATUAL | \n",
" ESTOQUE EM TRANSITO | \n",
" PEDIDO PENDENTE | \n",
" DDV PREVISTO | \n",
" COBERTURA ATUAL | \n",
" COBERTURA ATUAL + TRANSITO | \n",
" Arquivo_Origem | \n",
" SKU_FINAL | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 90495 | \n",
" - | \n",
" 20005 | \n",
" 100.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" BOT.csv | \n",
" 90495 | \n",
"
\n",
" \n",
" | 1 | \n",
" 90246 | \n",
" - | \n",
" 4560 | \n",
" 0.0 | \n",
" NaN | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" BOT.csv | \n",
" 90246 | \n",
"
\n",
" \n",
" | 2 | \n",
" 90246 | \n",
" - | \n",
" 5699 | \n",
" 0.0 | \n",
" NaN | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" BOT.csv | \n",
" 90246 | \n",
"
\n",
" \n",
" | 3 | \n",
" 90246 | \n",
" - | \n",
" 12522 | \n",
" 0.0 | \n",
" NaN | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" BOT.csv | \n",
" 90246 | \n",
"
\n",
" \n",
" | 4 | \n",
" 90246 | \n",
" - | \n",
" 12817 | \n",
" 0.0 | \n",
" NaN | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" BOT.csv | \n",
" 90246 | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 441216 | \n",
" 1594 | \n",
" - | \n",
" 20995 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" QDB.csv | \n",
" 1594 | \n",
"
\n",
" \n",
" | 441217 | \n",
" 1594 | \n",
" - | \n",
" 20998 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" QDB.csv | \n",
" 1594 | \n",
"
\n",
" \n",
" | 441218 | \n",
" 1594 | \n",
" - | \n",
" 21001 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" QDB.csv | \n",
" 1594 | \n",
"
\n",
" \n",
" | 441219 | \n",
" 1594 | \n",
" - | \n",
" 21278 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" QDB.csv | \n",
" 1594 | \n",
"
\n",
" \n",
" | 441220 | \n",
" 1594 | \n",
" - | \n",
" 21383 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" QDB.csv | \n",
" 1594 | \n",
"
\n",
" \n",
"
\n",
"
441221 rows × 11 columns
\n",
"
"
],
"text/plain": [
" SKU SKU_PARA PDV ESTOQUE ATUAL ESTOQUE EM TRANSITO \\\n",
"0 90495 - 20005 100.0 0.0 \n",
"1 90246 - 4560 0.0 NaN \n",
"2 90246 - 5699 0.0 NaN \n",
"3 90246 - 12522 0.0 NaN \n",
"4 90246 - 12817 0.0 NaN \n",
"... ... ... ... ... ... \n",
"441216 1594 - 20995 0.0 0.0 \n",
"441217 1594 - 20998 0.0 0.0 \n",
"441218 1594 - 21001 0.0 0.0 \n",
"441219 1594 - 21278 0.0 0.0 \n",
"441220 1594 - 21383 0.0 0.0 \n",
"\n",
" PEDIDO PENDENTE DDV PREVISTO COBERTURA ATUAL \\\n",
"0 0.0 NaN NaN \n",
"1 0.0 NaN NaN \n",
"2 0.0 NaN NaN \n",
"3 0.0 NaN NaN \n",
"4 0.0 NaN NaN \n",
"... ... ... ... \n",
"441216 0.0 NaN NaN \n",
"441217 0.0 NaN NaN \n",
"441218 0.0 NaN NaN \n",
"441219 0.0 NaN NaN \n",
"441220 0.0 NaN NaN \n",
"\n",
" COBERTURA ATUAL + TRANSITO Arquivo_Origem SKU_FINAL \n",
"0 NaN BOT.csv 90495 \n",
"1 NaN BOT.csv 90246 \n",
"2 NaN BOT.csv 90246 \n",
"3 NaN BOT.csv 90246 \n",
"4 NaN BOT.csv 90246 \n",
"... ... ... ... \n",
"441216 NaN QDB.csv 1594 \n",
"441217 NaN QDB.csv 1594 \n",
"441218 NaN QDB.csv 1594 \n",
"441219 NaN QDB.csv 1594 \n",
"441220 NaN QDB.csv 1594 \n",
"\n",
"[441221 rows x 11 columns]"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_estoque"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"c:\\Users\\joao.herculano\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\openpyxl\\styles\\stylesheet.py:237: UserWarning: Workbook contains no default style, apply openpyxl's default\n",
" warn(\"Workbook contains no default style, apply openpyxl's default\")\n"
]
}
],
"source": [
"df_bi_preco = pd.read_excel(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\DB_PROMOÇÕES\\BOTICARIO\\C09\\arquivos pra gerar\\preços bi\\TABELA DE PREÇOS (4).xlsx\")\n",
"\n",
"df_bi_preco = df_bi_preco.drop(columns=['Descrição','Tipo Preço','CATEGORIA','LINHA','MARCA'])\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(44744, 31)"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final = pd.merge(left=df_tabela,right=df_pdv,on='MATCH',how='inner')\n",
"\n",
"df_final = df_final.drop_duplicates()\n",
"\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(44744, 62)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final['PDV'] = df_final['PDV'].astype('Int64')\n",
"df_final['Código'] = df_final['Código'].astype('Int64')\n",
"\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_draft,left_on=['PDV','Código'],right_on=['PDV','SKU'],how='left')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"26447 2.0\n",
"Name: Histórico de Vendas do Ciclo 202505, dtype: float64"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final[(df_final['Código'] == 52023) & (df_final['PDV'] == 23712)]['Histórico de Vendas do Ciclo 202505']"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['Sortimento P', 'Sortimento M',\n",
" 'Sortimento G','MARCA','SKU'])"
]
},
{
"cell_type": "code",
"execution_count": 21,
"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"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"#ignorando a PDV que ainda não está online\n",
"df_pdv = df_pdv[df_pdv['DESCRIÇÃO PDV'] != '23813-COMERCIO-HIB VALENTE']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**ALTERAR NOME DA COLUNA \"ARQUIVO_ORIGEM\" PARA UMA DAS OPÇÕES ABAIXO:**\n",
"\n",
"*BOT.csv* \n",
"\n",
"*EUD.csv*\n",
"\n",
"*QDB.csv*"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Ciclo | \n",
" INICIO CICLO | \n",
" FIM CICLO | \n",
" DURAÇÃO | \n",
" Date | \n",
" NUM_CICLO | \n",
" ANO_CICLO | \n",
" CICLOMAIS2 | \n",
" dias_ate_inicio | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2199 | \n",
" C202510 | \n",
" 2025-06-30 | \n",
" 2025-07-20 | \n",
" 21 | \n",
" 2025-06-30 | \n",
" 10 | \n",
" C2025 | \n",
" C202512 | \n",
" 28 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Ciclo INICIO CICLO FIM CICLO DURAÇÃO Date NUM_CICLO \\\n",
"2199 C202510 2025-06-30 2025-07-20 21 2025-06-30 10 \n",
"\n",
" ANO_CICLO CICLOMAIS2 dias_ate_inicio \n",
"2199 C2025 C202512 28 "
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"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",
"calendario['ANO_CICLO'] = calendario['Ciclo'].str[0:5]\n",
"\n",
"\n",
"calendario = calendario[calendario['MARCA'] == \"BOTICARIO\"]\n",
"\n",
"calendario = calendario.drop(columns='MARCA')\n",
"\n",
"calendario['CICLOMAIS2'] = calendario['ANO_CICLO'].astype(str) + (calendario['NUM_CICLO'].astype(int) + 2).astype(str).str.zfill(2) # >>>>>>>>> MUDAR PRA CICLO CORRETO \n",
"\n",
"ciclo_mais2 = calendario[calendario['Date'].dt.normalize() == today]['CICLOMAIS2'].iloc[0]\n",
"\n",
"\n",
"# Filter rows where date matches today\n",
"filtered_calendario = calendario[calendario['Ciclo'] == ciclo_mais2][:1]\n",
"\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\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"filtered_calendario['MATCH'] = 1"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"df_pdv['UF'] = np.where(df_pdv['UF'] == 'VDC','BA',df_pdv['UF'])"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"#df_tabela = df_tabela[(df_tabela['Tipo de promoção'] == \"Revendedor\" ) | (df_tabela['Tipo de promoção'] == \"Promoções\") |(df_tabela['Tipo de promoção'] == \"Promoções | Revendedor\" )]"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"df_draft['PDV'] = df_draft['PDV'].astype(str)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(44744, 62)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"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='inner')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(54425, 72)"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final['Código'] = df_final['Código'].astype('Int64') \n",
"df_final['PDV'] = df_final['PDV'].astype('Int64') \n",
"\n",
"df_estoque['PDV'] = df_estoque['PDV'].astype('Int64') \n",
"df_estoque['SKU_FINAL'] = df_estoque['SKU_FINAL'].astype('Int64') \n",
"\n",
"df_final = pd.merge(left=df_final,right=df_estoque,right_on=['PDV','SKU_FINAL'],left_on=['PDV','Código'],how='left')\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(54425, 76)"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final['Código'] = df_final['Código'].astype('str')\n",
"\n",
"df_bi_preco['SKU2'] = df_bi_preco['SKU2'].astype('str')\n",
"\n",
"df_final = pd.merge(left=df_final,right=df_bi_preco,right_on=['UF','SKU2'],left_on=['UF','Código'],how='left')\n",
"df_final.shape "
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(54514, 80)"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_bi_preco['SKU1'] = df_bi_preco['SKU1'].astype(str).str.replace('.0','',regex=False) \n",
"\n",
"df_final = pd.merge(left=df_final,right=df_bi_preco[['SKU1', 'SKU2', 'UF', 'PC', 'PV']],right_on=['UF','SKU1'],left_on=['UF','Código'],how='left')\n",
"df_final.shape "
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"df_final['PRECO DE COMPRA'] = np.where(~df_final['PC_x'].isna(),df_final['PC_x'],df_final['PC_y'])\n",
"\n",
"df_final['PRECO DE VENDA'] = np.where(~df_final['PV_x'].isna(),df_final['PV_x'],df_final['PV_y'])\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"CANAL\n",
"TODOS 42336\n",
"VD 12178\n",
"Name: count, dtype: int64"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"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": 34,
"metadata": {},
"outputs": [],
"source": [
"df_estoque = df_estoque.rename(columns={'SKU_FINAL':'SKU_PARA_VALIDACAO'})\n",
"\n",
"df_estoque['SKU_PARA_VALIDACAO'] = df_estoque['SKU_PARA_VALIDACAO'].astype('Int64')\n",
"\n",
"df_final = pd.merge( left= df_final, right = df_estoque[['SKU_PARA_VALIDACAO','Arquivo_Origem']], left_on= 'SKU', right_on='SKU_PARA_VALIDACAO', how='left')\n",
"\n",
"df_final = df_final.drop_duplicates()"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.drop(columns=['SKU1_x','SKU1_y','SKU2_x','SKU2_y','PC_x', 'PV_x','PC_y', 'PV_y','Subcategoria',\n",
"'Carteira Bloqueada Para Novos Pedidos',\n",
"'Quantidade por caixa'\n",
"])"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"df_final['UFPRODUTO'] = df_final['UF'].astype(str) + df_final['SKU'].astype(str)\n"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"df_final['Projeção Próximo Ciclo + 1'] =df_final['Projeção Próximo Ciclo + 1'] - df_final['Projeção Próximo Ciclo'] # projeção do ciclo em estudo"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [],
"source": [
"df_final['Data Prevista Regularização'] = df_final['Data Prevista Regularização'].astype(str).replace('0','REGULAR')"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.rename(columns={'Compra inteligente Próximo Ciclo + 1':'Compra inteligente Próximo Ciclo','Arquivo_Origem': 'MARCA'})"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"np.int64(0)"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final = df_final[~df_final['Marca'].isna()]\n",
"df_final['Marca'].isna().sum()"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(54514, 74)"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final = df_final.drop_duplicates()\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [],
"source": [
"df_final[df_final.columns[26:43]] = df_final[df_final.columns[26:43]].fillna(0)\n"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Histórico de Vendas do Ciclo 202408',\n",
" 'Histórico de Vendas do Ciclo 202409',\n",
" 'Histórico de Vendas do Ciclo 202410',\n",
" 'Histórico de Vendas do Ciclo 202411',\n",
" 'Histórico de Vendas do Ciclo 202412',\n",
" 'Histórico de Vendas do Ciclo 202413',\n",
" 'Histórico de Vendas do Ciclo 202414',\n",
" 'Histórico de Vendas do Ciclo 202415',\n",
" 'Histórico de Vendas do Ciclo 202416',\n",
" 'Histórico de Vendas do Ciclo 202417',\n",
" 'Histórico de Vendas do Ciclo 202501',\n",
" 'Histórico de Vendas do Ciclo 202502',\n",
" 'Histórico de Vendas do Ciclo 202503',\n",
" 'Histórico de Vendas do Ciclo 202504',\n",
" 'Histórico de Vendas do Ciclo 202505',\n",
" 'Histórico de Vendas do Ciclo 202506',\n",
" 'Histórico de Vendas do Ciclo 202507',\n",
" 'Histórico de Vendas do Ciclo Atual'],\n",
" dtype='object')"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final.columns[26:44]"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [],
"source": [
"# Define list of target columns\n",
"sales_2024_cols = df_final.columns[26:44]\n",
"# Create a new column with the row-wise max\n",
"df_final['PICO DE VENDAS 2024'] = df_final[sales_2024_cols].max(axis=1)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Histórico de Vendas do Ciclo 202502',\n",
" 'Histórico de Vendas do Ciclo 202503',\n",
" 'Histórico de Vendas do Ciclo 202504',\n",
" 'Histórico de Vendas do Ciclo 202505',\n",
" 'Histórico de Vendas do Ciclo 202506',\n",
" 'Histórico de Vendas do Ciclo 202507',\n",
" 'Histórico de Vendas do Ciclo Atual'],\n",
" dtype='object')"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final.columns[37:44]"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [],
"source": [
"vendas_6_meses = df_final.columns[37:44]\n",
"\n",
"df_final['Pico Vendas Ultimos 6 ciclos'] = df_final[vendas_6_meses].max(axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Histórico de Vendas do Ciclo 202502',\n",
" 'Histórico de Vendas do Ciclo 202503',\n",
" 'Histórico de Vendas do Ciclo 202504',\n",
" 'Histórico de Vendas do Ciclo 202505',\n",
" 'Histórico de Vendas do Ciclo 202506',\n",
" 'Histórico de Vendas do Ciclo 202507',\n",
" 'Histórico de Vendas do Ciclo Atual'],\n",
" dtype='object')"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final.columns[37:44]"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_37488\\2592201544.py:24: DeprecationWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n",
" crescimento_por_pdv = df_final.groupby('PDV').apply(calcular_crescimento)\n"
]
}
],
"source": [
"# Define as colunas mensais\n",
"colunas_mensais = df_final.columns[26:43]\n",
"\n",
"# Agrupa por PDV e calcula crescimento médio por PDV\n",
"def calcular_crescimento(grupo):\n",
" soma_mensal = grupo[colunas_mensais].sum() # soma por mês\n",
" variacao_mensal = soma_mensal.pct_change().dropna() # variação percentual mês a mês\n",
" variacao_mensal = variacao_mensal[np.isfinite(variacao_mensal)]\n",
"\n",
" if len(variacao_mensal) == 0:\n",
" return pd.Series({'CRESCIMENTO': np.nan})\n",
"\n",
" media = variacao_mensal.mean()\n",
" desvio = variacao_mensal.std()\n",
"\n",
" limite_sup = media + 2 * desvio\n",
" limite_inf = media - 2 * desvio\n",
"\n",
" variacoes_filtradas = variacao_mensal[variacao_mensal.between(limite_inf, limite_sup)]\n",
" crescimento = round(variacoes_filtradas.mean(), 4)\n",
" return pd.Series({'CRESCIMENTO': crescimento})\n",
"\n",
"# Aplica a função por PDV\n",
"crescimento_por_pdv = df_final.groupby('PDV').apply(calcular_crescimento)\n",
"\n",
"# Merge do resultado de volta no dataframe original\n",
"df_final = df_final.merge(crescimento_por_pdv, on='PDV', how='left')\n"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"np.float64(0.0528)"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Suponha que os meses estão nas colunas 10 a 26 (17 colunas = 17 meses)\n",
"colunas_mensais = df_final.columns[26:43]\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_GERAL'] = CRESCIMENTO\n",
"\n",
"CRESCIMENTO\n"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" CANAL | \n",
" med_por_canal | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" TODOS | \n",
" 92.5 | \n",
"
\n",
" \n",
" | 1 | \n",
" VD | \n",
" 715.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" CANAL med_por_canal\n",
"0 TODOS 92.5\n",
"1 VD 715.0"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vendas_todos_historicos = df_final.columns[26:44]\n",
"\n",
"df_final['MEDIANA DO HISTÓRICO'] = df_final[vendas_todos_historicos].median(axis=1)\n",
"\n",
"df_final['MEDIA DO HISTÓRICO'] = df_final[vendas_todos_historicos].mean(axis=1)\n",
"\n",
"medi = df_final.groupby(['CANAL'])['MEDIANA DO HISTÓRICO'].max().reset_index()\n",
"medi = medi.rename(columns={'MEDIANA DO HISTÓRICO':'med_por_canal'})\n",
"\n",
"df_final = pd.merge(left=df_final, right=medi,on='CANAL',how='inner')\n",
"\n",
"medi"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'202410'"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final.columns[28:29].str.split(\" \")[0][-1]"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [],
"source": [
"mesmo_ciclo_ano_passado = df_final.columns[28:29]\n",
"ciclo_ano_passado = df_final.columns[28:29].str.split(\" \")[0][-1]\n",
"df_final[ciclo_ano_passado] = df_final[mesmo_ciclo_ano_passado]"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(54514, 84)"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final['CRESCIMENTO_FINAL'] = df_final['CRESCIMENTO_GERAL'] + df_final['CRESCIMENTO'] #crescimento do pdv\n",
"\n",
"df_final['CRESCIMENTO_FINAL'] = np.where(df_final['CRESCIMENTO_GERAL'] + df_final['CRESCIMENTO']>0.8,0.8,df_final['CRESCIMENTO_GERAL'] + df_final['CRESCIMENTO'])\n",
"\n",
"df_final['CRESCIMENTO_FINAL'] = np.where(df_final['CRESCIMENTO_GERAL'] + df_final['CRESCIMENTO']<0,0,df_final['CRESCIMENTO_GERAL'] + df_final['CRESCIMENTO'])\n",
"\n",
"df_final['MEDIANA DO HISTÓRICO'] = np.where(df_final['MEDIANA DO HISTÓRICO']==0,df_final['MEDIA DO HISTÓRICO'] ,df_final['MEDIANA DO HISTÓRICO'])\n",
"\n",
"# Primeiro cálculo intermediário\n",
"df_final['PV GINSENG'] = np.where(df_final['CRESCIMENTO_FINAL'] * df_final[ciclo_ano_passado] + df_final[ciclo_ano_passado] <1,\n",
" round(df_final['CRESCIMENTO_FINAL'] * df_final['MEDIANA DO HISTÓRICO']+ df_final['MEDIANA DO HISTÓRICO'],0), \n",
" round(df_final['CRESCIMENTO_FINAL']*df_final[ciclo_ano_passado]+df_final[ciclo_ano_passado],0))\n",
"\n",
"\n",
"df_final.shape"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Histórico de Vendas do Ciclo 202408',\n",
" 'Histórico de Vendas do Ciclo 202409',\n",
" 'Histórico de Vendas do Ciclo 202410',\n",
" 'Histórico de Vendas do Ciclo 202411',\n",
" 'Histórico de Vendas do Ciclo 202412',\n",
" 'Histórico de Vendas do Ciclo 202413',\n",
" 'Histórico de Vendas do Ciclo 202414',\n",
" 'Histórico de Vendas do Ciclo 202415',\n",
" 'Histórico de Vendas do Ciclo 202416',\n",
" 'Histórico de Vendas do Ciclo 202417',\n",
" 'Histórico de Vendas do Ciclo 202501',\n",
" 'Histórico de Vendas do Ciclo 202502',\n",
" 'Histórico de Vendas do Ciclo 202503'],\n",
" dtype='object')"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final.columns[26:39]"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [],
"source": [
"df_final = df_final.rename(columns={df_final.columns[39]: \"C-4\", df_final.columns[40]: \"C-3\",df_final.columns[41]: \"C-2\",df_final.columns[42]: \"C-1\"})"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [],
"source": [
"df_final.drop(columns=df_final.columns[26:39], inplace=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [],
"source": [
"# List all columns except the two\n",
"cols_to_group_by = df_final.columns.difference(['DDV PREVISTO', 'COBERTURA ATUAL'])\n",
"\n",
"# Group and aggregate\n",
"df_final_dedup = (\n",
" df_final\n",
" .groupby(list(cols_to_group_by), dropna=False)[['DDV PREVISTO', 'COBERTURA ATUAL']]\n",
" .max()\n",
" .reset_index()\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['DDV PREVISTO'] = df_final_dedup['DDV PREVISTO'].fillna(0.01)\n"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"158 2.0\n",
"159 1.0\n",
"160 0.0\n",
"327 0.0\n",
"328 0.0\n",
" ... \n",
"54257 18.0\n",
"54347 32.0\n",
"54440 0.0\n",
"54441 112.0\n",
"54509 694.0\n",
"Name: C-3, Length: 731, dtype: float64"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final_dedup[(df_final['PDV'] == 23712)]['C-3']"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['DDV PREVISTO'] = np.where(\n",
" df_final_dedup['DDV PREVISTO'] == 0,\n",
" 0.01,\n",
" df_final_dedup['DDV PREVISTO']\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['202410', 'ANALISTA', 'Arquivo_Origem_x', 'Arquivo_Origem_y',\n",
" 'Ação consumidor', 'Ação revendedor', 'C-1', 'C-2', 'C-3', 'C-4',\n",
" 'CANAL', 'COBERTURA ATUAL + TRANSITO', 'CRESCIMENTO',\n",
" 'CRESCIMENTO_FINAL', 'CRESCIMENTO_GERAL', 'Canal', 'Categoria',\n",
" 'Catálogo', 'Ciclo_x', 'Ciclo_y', 'Classe', 'Código', 'DESCRIÇÃO PDV',\n",
" 'DURAÇÃO', 'Data Prevista Regularização', 'Descrição', 'Dias sem venda',\n",
" 'ESTOQUE ATUAL', 'ESTOQUE EM TRANSITO', 'Estoque Atual',\n",
" 'Estoque em Transito', 'FIM CICLO', 'Foco',\n",
" 'Histórico de Vendas do Ciclo 202407',\n",
" 'Histórico de Vendas do Ciclo Atual', 'IAF', 'INICIO CICLO',\n",
" 'Item Desativado', 'MATCH', 'MEDIA DO HISTÓRICO',\n",
" 'MEDIANA DO HISTÓRICO', 'Marca', 'PDV', 'PEDIDO PENDENTE',\n",
" 'PICO DE VENDAS 2024', 'PRECO DE COMPRA', 'PRECO DE VENDA',\n",
" 'PV GINSENG', 'Pedido Pendente', 'Percentual de desconto consumidor',\n",
" 'Percentual de desconto revendedor', 'Pico Vendas Ultimos 6 ciclos',\n",
" 'Projeção Próximo Ciclo', 'Projeção Próximo Ciclo + 1',\n",
" 'Promoção Próximo Ciclo + 1', 'Região', 'SKU', 'SKU_FINAL', 'SKU_PARA',\n",
" 'SKU_PARA_VALIDACAO', 'SUPERVISOR', 'Tipo de pedido', 'Tipo de produto',\n",
" 'Tipo de promoção', 'UF', 'UFPRODUTO', 'Unidade de negócio',\n",
" 'dias_ate_inicio', 'med_por_canal', 'DDV PREVISTO', 'COBERTURA ATUAL'],\n",
" dtype='object')"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final_dedup.columns"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['EST PROJE FINAL CICLO ATUAL'] = (df_final_dedup['Estoque Atual'] + df_final_dedup['Estoque em Transito']) - round(df_final_dedup['dias_ate_inicio'] * df_final_dedup['DDV PREVISTO'],0)"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['EST PROJE FINAL CICLO ATUAL'] = np.where(df_final_dedup['EST PROJE FINAL CICLO ATUAL']<0,0,df_final_dedup['EST PROJE FINAL CICLO ATUAL'])"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['VENDAS R$ PV GINSENG'] = df_final_dedup['PRECO DE VENDA'] * df_final_dedup['PV GINSENG']"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['SKU', 'SKU_PARA', 'PDV', 'ESTOQUE ATUAL', 'ESTOQUE EM TRANSITO',\n",
" 'PEDIDO PENDENTE', 'DDV PREVISTO', 'COBERTURA ATUAL',\n",
" 'COBERTURA ATUAL + TRANSITO', 'Arquivo_Origem', 'SKU_PARA_VALIDACAO'],\n",
" dtype='object')"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_estoque.columns"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('Ação consumidor',\n",
" 'Percentual de desconto consumidor',\n",
" 'Ação revendedor',\n",
" 'Percentual de desconto revendedor',\n",
" '202408')"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Columns to bring up front\n",
"priority_cols = [\n",
" 'SKU',\t'Marca',\t'INICIO CICLO',\n",
" 'FIM CICLO',\t'DURAÇÃO',\t'PRECO DE COMPRA',\t'PRECO DE VENDA',\n",
" 'UFPRODUTO',\t'Item Desativado',\t'Data Prevista Regularização',\n",
" 'ANALISTA',\t'UF',\t'CANAL',\t'PDV',\t'DESCRIÇÃO PDV',\t'Classe',\n",
" 'Descrição',\t'Categoria',\n",
"\t'ESTOQUE ATUAL', 'ESTOQUE EM TRANSITO',\t'COBERTURA ATUAL',\n",
" 'Pedido Pendente',\t'PICO DE VENDAS 2024','Pico Vendas Ultimos 6 ciclos',\n",
" 'C-4',\t'C-3',\t'C-2',\t'C-1',\t'Histórico de Vendas do Ciclo Atual',\n",
" 'Dias sem venda'\n",
"]\n",
"\n",
"# All remaining columns\n",
"other_cols = [col for col in df_final_dedup.columns if col not in priority_cols]\n",
"\n",
"# Reorder\n",
"'Ação consumidor', 'Percentual de desconto consumidor', 'Ação revendedor', 'Percentual de desconto revendedor', '202408'\n"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [],
"source": [
"#df_final_dedup = df_final_dedup[priority_cols + other_cols]\n"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['RBV 202406'] = df_final_dedup['PRECO DE VENDA'] * df_final_dedup[ciclo_ano_passado] "
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['COB PROJETADA'] = np.where(\n",
" df_final_dedup['DDV PREVISTO'] != 0,\n",
" (df_final_dedup['EST PROJE FINAL CICLO ATUAL'] + df_final_dedup['PV GINSENG']) / df_final_dedup['DDV PREVISTO'],\n",
" 999)\n"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup.drop(df_final_dedup.columns[39:40], axis=1, inplace=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup.drop(columns=['dias_ate_inicio','SKU_FINAL',\n",
" 'CRESCIMENTO'],inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [],
"source": [
"#df_final_dedup['MARCA'] = df_final_dedup['MARCA'].str.replace('.csv','',regex=False)"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['COB PROJETADA'] = df_final_dedup['COB PROJETADA'].fillna(999)"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'BOT'"
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"marca_promo = df_estoque['Arquivo_Origem'].iloc[0].replace('.csv','')\n",
"marca_promo"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['INICIO CICLO'] = pd.to_datetime(df_final_dedup['INICIO CICLO'], dayfirst=True).dt.strftime('%d/%m/%Y')\n",
"\n",
"df_final_dedup['FIM CICLO'] = pd.to_datetime(df_final_dedup['FIM CICLO'], dayfirst=True).dt.strftime('%d/%m/%Y')"
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['Percentual de desconto revendedor'] = np.where((df_final_dedup['Percentual de desconto revendedor'].isna()) & (~df_final_dedup['Percentual de desconto consumidor'].isna()),df_final_dedup['Percentual de desconto consumidor'],df_final_dedup['Percentual de desconto revendedor'])"
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {},
"outputs": [],
"source": [
"df_pdv_origi['PDV'] = df_pdv_origi['PDV'].astype('Int64')\n",
"df_final_dedup['PDV'] = df_final_dedup['PDV'].astype('Int64')\n",
"\n",
"\n",
"df_final_dedup = pd.merge(left=df_final_dedup,right=df_pdv_origi[['PDV','CANAL','UF']],how='inner',on='PDV')"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {},
"outputs": [],
"source": [
"df_vdc = pd.read_csv(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\SUPRIMENTOS\\DB_PROMOÇÕES\\BOTICARIO\\C10\\VENDA VITORIA 2024\\VENDA VITORIA.csv\")\n",
"\n",
"df_vdc['PRODUTO'] = df_vdc['PRODUTO'].astype('Int64')\n",
"\n",
"df_final_dedup['Código'] = df_final_dedup['Código'].astype('Int64')\n",
"\n",
"df_final_dedup =pd.merge(left=df_final_dedup,right=df_vdc[['PDV GINSENG','PRODUTO',ciclo_ano_passado]],left_on= ['PDV','Código'],right_on= ['PDV GINSENG','PRODUTO'],how='left' )\n",
"\n",
"df_final_dedup['202410_y'] = df_final_dedup['202410_y'].fillna(0)"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 202410_x | \n",
" ANALISTA | \n",
" Arquivo_Origem_x | \n",
" Arquivo_Origem_y | \n",
" Ação consumidor | \n",
" Ação revendedor | \n",
" C-1 | \n",
" C-2 | \n",
" C-3 | \n",
" C-4 | \n",
" ... | \n",
" COBERTURA ATUAL | \n",
" EST PROJE FINAL CICLO ATUAL | \n",
" VENDAS R$ PV GINSENG | \n",
" RBV 202406 | \n",
" COB PROJETADA | \n",
" CANAL_y | \n",
" UF_y | \n",
" PDV GINSENG | \n",
" PRODUTO | \n",
" 202410_y | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0.0 | \n",
" DANIEL | \n",
" BOT.csv | \n",
" BOT.csv | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" ... | \n",
" 45.0 | \n",
" 7.0 | \n",
" NaN | \n",
" NaN | \n",
" 700.0 | \n",
" LJ | \n",
" VDC | \n",
" NaN | \n",
" <NA> | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 0.0 | \n",
" DANIEL | \n",
" BOT.csv | \n",
" BOT.csv | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" ... | \n",
" 45.0 | \n",
" 4.0 | \n",
" NaN | \n",
" NaN | \n",
" 400.0 | \n",
" VD | \n",
" VDC | \n",
" 23703.0 | \n",
" 53901 | \n",
" 2.0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 0.0 | \n",
" DANIEL | \n",
" BOT.csv | \n",
" BOT.csv | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 2.0 | \n",
" ... | \n",
" 0.0 | \n",
" 0.0 | \n",
" 75.9 | \n",
" 0.0 | \n",
" 50.0 | \n",
" HIB | \n",
" AL | \n",
" NaN | \n",
" <NA> | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 3 | \n",
" 0.0 | \n",
" DANIEL | \n",
" BOT.csv | \n",
" BOT.csv | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" 0.0 | \n",
" 1.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" ... | \n",
" 50.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" LJ | \n",
" BA | \n",
" NaN | \n",
" <NA> | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 4 | \n",
" 0.0 | \n",
" DANIEL | \n",
" BOT.csv | \n",
" BOT.csv | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. | \n",
" 3.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 1.0 | \n",
" ... | \n",
" 260.0 | \n",
" 12.0 | \n",
" 75.9 | \n",
" 0.0 | \n",
" 260.0 | \n",
" LJ | \n",
" BA | \n",
" NaN | \n",
" <NA> | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
5 rows × 76 columns
\n",
"
"
],
"text/plain": [
" 202410_x ANALISTA Arquivo_Origem_x Arquivo_Origem_y \\\n",
"0 0.0 DANIEL BOT.csv BOT.csv \n",
"1 0.0 DANIEL BOT.csv BOT.csv \n",
"2 0.0 DANIEL BOT.csv BOT.csv \n",
"3 0.0 DANIEL BOT.csv BOT.csv \n",
"4 0.0 DANIEL BOT.csv BOT.csv \n",
"\n",
" Ação consumidor \\\n",
"0 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. \n",
"1 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. \n",
"2 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. \n",
"3 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. \n",
"4 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. \n",
"\n",
" Ação revendedor C-1 C-2 C-3 C-4 ... \\\n",
"0 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. 0.0 0.0 0.0 0.0 ... \n",
"1 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. 0.0 0.0 0.0 0.0 ... \n",
"2 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. 0.0 0.0 0.0 2.0 ... \n",
"3 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. 0.0 1.0 0.0 0.0 ... \n",
"4 ACESSÓRIOS SELECIONADOS COM ATÉ 15% DE DESCONTO. 3.0 0.0 0.0 1.0 ... \n",
"\n",
" COBERTURA ATUAL EST PROJE FINAL CICLO ATUAL VENDAS R$ PV GINSENG \\\n",
"0 45.0 7.0 NaN \n",
"1 45.0 4.0 NaN \n",
"2 0.0 0.0 75.9 \n",
"3 50.0 0.0 0.0 \n",
"4 260.0 12.0 75.9 \n",
"\n",
" RBV 202406 COB PROJETADA CANAL_y UF_y PDV GINSENG PRODUTO 202410_y \n",
"0 NaN 700.0 LJ VDC NaN 0.0 \n",
"1 NaN 400.0 VD VDC 23703.0 53901 2.0 \n",
"2 0.0 50.0 HIB AL NaN 0.0 \n",
"3 0.0 0.0 LJ BA NaN 0.0 \n",
"4 0.0 260.0 LJ BA NaN 0.0 \n",
"\n",
"[5 rows x 76 columns]"
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final_dedup.head()"
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup['202410_x'] = np.where(df_final_dedup['202410_y']>0,df_final_dedup['202410_y'],df_final_dedup['202410_x'])"
]
},
{
"cell_type": "code",
"execution_count": 81,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup = df_final_dedup.drop(columns=['Arquivo_Origem_x','Arquivo_Origem_y','CANAL_x','Canal',\n",
" 'Ciclo_x','Ciclo_y','DURAÇÃO','FIM CICLO','Foco','INICIO CICLO','MATCH',\n",
" 'PRECO DE COMPRA','SKU','SKU_PARA','SKU_PARA_VALIDACAO',\n",
" 'Tipo de pedido',\t'Tipo de produto','UFPRODUTO','Unidade de negócio','EST PROJE FINAL CICLO ATUAL',\n",
" 'UF_x','RBV 202406','Região','Catálogo','SKU','VENDAS R$ PV GINSENG','Data Prevista Regularização',\n",
" 'IAF', 'Item Desativado','Tipo de promoção','PDV GINSENG','PRODUTO','202410_y',\n",
" 'ESTOQUE ATUAL', 'ESTOQUE EM TRANSITO','COBERTURA ATUAL + TRANSITO',\n",
" 'DDV PREVISTO',\t'COB PROJETADA','COBERTURA ATUAL',\n",
" 'CRESCIMENTO_FINAL',\t'CRESCIMENTO_GERAL','med_por_canal','PEDIDO PENDENTE'])"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup = df_final_dedup.rename(columns={'CANAL_y':'CANAL','UF_y':'UF','Marca':'LINHA','202410_x':'202410'})\n"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['202410', 'ANALISTA', 'Ação consumidor', 'Ação revendedor', 'C-1',\n",
" 'C-2', 'C-3', 'C-4', 'Categoria', 'Classe', 'Código', 'DESCRIÇÃO PDV',\n",
" 'Descrição', 'Dias sem venda', 'Estoque Atual', 'Estoque em Transito',\n",
" 'Histórico de Vendas do Ciclo 202407',\n",
" 'Histórico de Vendas do Ciclo Atual', 'MEDIANA DO HISTÓRICO', 'LINHA',\n",
" 'PDV', 'PICO DE VENDAS 2024', 'PRECO DE VENDA', 'PV GINSENG',\n",
" 'Pedido Pendente', 'Percentual de desconto consumidor',\n",
" 'Percentual de desconto revendedor', 'Pico Vendas Ultimos 6 ciclos',\n",
" 'Projeção Próximo Ciclo', 'Projeção Próximo Ciclo + 1',\n",
" 'Promoção Próximo Ciclo + 1', 'SUPERVISOR', 'CANAL', 'UF'],\n",
" dtype='object')"
]
},
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final_dedup.columns"
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"158 2.0\n",
"159 1.0\n",
"160 0.0\n",
"327 0.0\n",
"328 0.0\n",
" ... \n",
"54257 18.0\n",
"54347 32.0\n",
"54440 0.0\n",
"54441 112.0\n",
"54509 694.0\n",
"Name: C-3, Length: 731, dtype: float64"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final_dedup[(df_final['PDV'] == 23712)]['C-3']"
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {},
"outputs": [],
"source": [
"priority_cols = ['SUPERVISOR','ANALISTA','UF','CANAL','LINHA','PDV','DESCRIÇÃO PDV','Código','Descrição','Categoria', \n",
"'Classe','Percentual de desconto consumidor','Ação consumidor','Percentual de desconto revendedor','Ação revendedor','C-1',\n",
"'C-2', 'C-3', 'C-4','Histórico de Vendas do Ciclo Atual','Estoque Atual','Estoque em Transito','Pedido Pendente',\n",
"'Projeção Próximo Ciclo + 1','Projeção Próximo Ciclo']\n",
"\n",
"# All remaining columns\n",
"other_cols = [col for col in df_final_dedup.columns if col not in priority_cols]\n",
"\n",
"# Reorder\n",
"df_final_dedup = df_final_dedup[priority_cols + other_cols]\n",
"\n",
"df_final_dedup['SUGESTÃO ABASTECIMENTO'] = ''\n"
]
},
{
"cell_type": "code",
"execution_count": 86,
"metadata": {},
"outputs": [],
"source": [
"df_final_dedup = df_final_dedup.drop_duplicates()"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"np.float64(157499.0)"
]
},
"execution_count": 87,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final_dedup['PV GINSENG'].sum()"
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"np.int64(0)"
]
},
"execution_count": 88,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_final_dedup[df_final_dedup['PDV'] == 23712]['PICO DE VENDAS 2024'].isna().sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Export to Excel\n",
"output_file = f'C:\\\\Users\\\\joao.herculano\\\\Documents\\\\promoção_{marca_promo}_{ciclo_mais2}.{hoje}.xlsx'\n",
"with pd.ExcelWriter(output_file, engine='openpyxl') as writer:\n",
" df_final_dedup.to_excel(writer, index=False)\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": "markdown",
"metadata": {},
"source": [
"coisas q saem\n",
"\n",
"Lançamento\n",
"Subcategoria\n",
"Projeção Próximo Ciclo \n",
"Promoção Próximo Ciclo\n",
"Compra inteligente semanal/Sugestão de compra\n",
"Compra inteligente Próximo Ciclo\n",
"Planograma\n",
"Carteira Bloqueada Para Novos Pedidos\n",
"Quantidade por caixa\n",
"Preço Sell In\n",
"Quantidade\n",
"Item analisado\n",
"Tipo Preço\n",
"\n",
">>>>>>>>>>>>>NAO ESTÁ PEGANDO O MERGE COM O DF_ESTOQUE\n",
"\n",
"\n",
"CRIAR PROJEÇÃO DE VENDA DO CICLO ATUAL\n",
"Compra inteligente Próximo Ciclo + 1 >>>>>>> RENAME PRA NOROMAL"
]
}
],
"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": 2
}