{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "de3d87c6", "metadata": {}, "outputs": [], "source": [ "import pyodbc\n", "import configparser\n", "import pandas as pd\n", "import numpy as np \n", "from datetime import datetime, time" ] }, { "cell_type": "code", "execution_count": 2, "id": "4c545066", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['C:\\\\Users\\\\joao.herculano\\\\GRUPO GINSENG\\\\Assistência Suprimentos - 2025\\\\CODIGOS\\\\relatório_improdutivo\\\\credenciais.ini']" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "config = configparser.ConfigParser()\n", "config.read(r\"C:\\Users\\joao.herculano\\GRUPO GINSENG\\Assistência Suprimentos - 2025\\CODIGOS\\relatório_improdutivo\\credenciais.ini\")\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "4f2890a0", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_35380\\87634967.py:28: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", " df_fne = pd.read_sql(query_fne, conn)\n", "C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_35380\\87634967.py:45: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", " df_pedidos = pd.read_sql(query_pedidos, conn)\n", "C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_35380\\87634967.py:52: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", " df_draft = pd.read_sql(query_draft, conn)\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CicloPDVcod_produtopedido_iddata_emissao_nfdata_pedidodata_prevista_atendimentofaturado_industriaquantidade_pedidastatussalescurvevalor_total_produtosnotaspedidosatendimento
0C202507125225275715159222025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000535Parcialmente AtendidoC45.363195312701652027060.142857
1C202507128175275715159182025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.00000002490Parcialmente AtendidoC217.713175412201652024910.266667
2C202507128178706615173062025-07-092025-05-22 00:00:00.00000002025-06-13 00:00:00.000000019ConcluídoC6.113175412201652066430.111111
3C202507128185275715159242025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000425Parcialmente AtendidoC36.297607778201652027070.16
4C202507128205275715159432025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000320Parcialmente AtendidoC27.212940384601652023690.15
\n", "
" ], "text/plain": [ " Ciclo PDV cod_produto pedido_id data_emissao_nf \\\n", "0 C202507 12522 52757 1515922 2025-07-09 \n", "1 C202507 12817 52757 1515918 2025-07-09 \n", "2 C202507 12817 87066 1517306 2025-07-09 \n", "3 C202507 12818 52757 1515924 2025-07-09 \n", "4 C202507 12820 52757 1515943 2025-07-09 \n", "\n", " data_pedido data_prevista_atendimento \\\n", "0 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "1 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "2 2025-05-22 00:00:00.0000000 2025-06-13 00:00:00.0000000 \n", "3 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "4 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "\n", " faturado_industria quantidade_pedida status salescurve \\\n", "0 5 35 Parcialmente Atendido C \n", "1 24 90 Parcialmente Atendido C \n", "2 1 9 Concluído C \n", "3 4 25 Parcialmente Atendido C \n", "4 3 20 Parcialmente Atendido C \n", "\n", " valor_total_produtos notas pedidos atendimento \n", "0 45.36 31953127 0165202706 0.142857 \n", "1 217.71 31754122 0165202491 0.266667 \n", "2 6.11 31754122 0165206643 0.111111 \n", "3 36.29 76077782 0165202707 0.16 \n", "4 27.21 29403846 0165202369 0.15 " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "conn = pyodbc.connect(\n", " f\"DRIVER={{SQL Server}};\"\n", " f\"SERVER={config['banco']['host']},1433;\"\n", " f\"DATABASE=GINSENG;\"\n", " f\"UID={config['banco']['user']};\"\n", " f\"PWD={config['banco']['password']}\")\n", "\n", "\n", "# 1. Puxa fne_pdv (já filtrado)\n", "query_fne = \"\"\"\n", "SELECT\n", " fne.cnpj_destinatario,\n", " fne.cnf AS Nota_Fiscal,\n", " CAST(fne.data_emissao AS date) AS data_emissao,\n", " fnei.codigo_pedido,\n", " fnei.n_item,\n", " fnei.cod_produto,\n", " fnei.produto,\n", " fnei.quantidade,\n", " fnei.valor_unitario,\n", " fnei.valor_total_produtos,\n", " b.PDV\n", "FROM fato_notas_entrada fne\n", "INNER JOIN fato_notas_entrada_itens fnei ON fne.chave = fnei.chave\n", "INNER JOIN base_pdvs b ON fne.cnpj_destinatario = b.CNPJ\n", "WHERE fne.data_emissao > '2025-07-01'\n", "\"\"\"\n", "df_fne = pd.read_sql(query_fne, conn)\n", "\n", "query_pedidos = \"\"\"\n", "SELECT\n", " sellOrders,\n", " sku,\n", " storeCode,\n", " MAX(quantity_accepted) AS quantity_accepted,\n", " MAX(status) AS status,\n", " MAX(pedido_id) AS pedido_id,\n", " MAX(p.[date]) AS [date],\n", " MAX(deliveryDate) AS deliveryDate,\n", " cd.Ciclo \n", "FROM produtos_pedidos p\n", "INNER JOIN ciclos_data_2025 cd on cd.[Date] = p.[date] and cd.MARCA ='BOT'\n", "GROUP BY sellOrders, sku, storeCode, cd.Ciclo \n", "\"\"\"\n", "df_pedidos = pd.read_sql(query_pedidos, conn)\n", "\n", "# 3. Puxa draft\n", "query_draft = \"\"\"\n", "SELECT loja_id, code, salescurve\n", "FROM draft\n", "\"\"\"\n", "df_draft = pd.read_sql(query_draft, conn)\n", "\n", "# ---- Fazendo os JOINs e agregações em Pandas ----\n", "\n", "# JOIN fne com pedidos\n", "df_join = df_fne.merge(df_pedidos, left_on=['codigo_pedido','cod_produto','PDV'],\n", " right_on=['sellOrders','sku','storeCode'], how=\"inner\")\n", "\n", "# JOIN com draft\n", "df_join = df_join.merge(df_draft, left_on=['PDV','cod_produto'],\n", " right_on=['loja_id','code'], how=\"inner\")\n", "\n", "# Agrupamento final\n", "df_result = (\n", " df_join.groupby(['Ciclo','PDV','cod_produto','pedido_id'])\n", " .agg(\n", " data_emissao_nf=('data_emissao','max'),\n", " data_pedido=('date','max'),\n", " data_prevista_atendimento=('deliveryDate','max'),\n", " faturado_industria=('quantidade','sum'),\n", " quantidade_pedida=('quantity_accepted','max'),\n", " status=('status','max'),\n", " salescurve=('salescurve','max'),\n", " valor_total_produtos=('valor_total_produtos','sum'),\n", " notas=('Nota_Fiscal', lambda x: ', '.join(sorted(set(x)))),\n", " pedidos=('codigo_pedido', lambda x: ', '.join(sorted(set(x))))\n", " )\n", " .reset_index()\n", ")\n", "\n", "# Calculando atendimento\n", "df_result['atendimento'] = (\n", " df_result['faturado_industria'] / df_result['quantidade_pedida'].replace(0, pd.NA)\n", ").round(2)\n", "\n", "df_result.head()" ] }, { "cell_type": "code", "execution_count": 4, "id": "b20bddba", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CicloPDVcod_produtopedido_iddata_emissao_nfdata_pedidodata_prevista_atendimentofaturado_industriaquantidade_pedidastatussalescurvevalor_total_produtosnotaspedidosatendimentociclo_anterior
0C202507125225275715159222025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000535Parcialmente AtendidoC45.363195312701652027060.142857C202506
1C202507128175275715159182025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.00000002490Parcialmente AtendidoC217.713175412201652024910.266667C202506
2C202507128178706615173062025-07-092025-05-22 00:00:00.00000002025-06-13 00:00:00.000000019ConcluídoC6.113175412201652066430.111111C202506
3C202507128185275715159242025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000425Parcialmente AtendidoC36.297607778201652027070.16C202506
4C202507128205275715159432025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000320Parcialmente AtendidoC27.212940384601652023690.15C202506
\n", "
" ], "text/plain": [ " Ciclo PDV cod_produto pedido_id data_emissao_nf \\\n", "0 C202507 12522 52757 1515922 2025-07-09 \n", "1 C202507 12817 52757 1515918 2025-07-09 \n", "2 C202507 12817 87066 1517306 2025-07-09 \n", "3 C202507 12818 52757 1515924 2025-07-09 \n", "4 C202507 12820 52757 1515943 2025-07-09 \n", "\n", " data_pedido data_prevista_atendimento \\\n", "0 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "1 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "2 2025-05-22 00:00:00.0000000 2025-06-13 00:00:00.0000000 \n", "3 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "4 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "\n", " faturado_industria quantidade_pedida status salescurve \\\n", "0 5 35 Parcialmente Atendido C \n", "1 24 90 Parcialmente Atendido C \n", "2 1 9 Concluído C \n", "3 4 25 Parcialmente Atendido C \n", "4 3 20 Parcialmente Atendido C \n", "\n", " valor_total_produtos notas pedidos atendimento ciclo_anterior \n", "0 45.36 31953127 0165202706 0.142857 C202506 \n", "1 217.71 31754122 0165202491 0.266667 C202506 \n", "2 6.11 31754122 0165206643 0.111111 C202506 \n", "3 36.29 76077782 0165202707 0.16 C202506 \n", "4 27.21 29403846 0165202369 0.15 C202506 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Extrair ano e ciclo\n", "df_result['ano'] = df_result['Ciclo'].str[1:5].astype(int)\n", "df_result['num_ciclo'] = df_result['Ciclo'].str[5:].astype(int)\n", "\n", "# Calcular ciclo anterior\n", "df_result['ciclo_anterior'] = df_result.apply(\n", " lambda row: f\"C{row['ano']}{row['num_ciclo']-1:02d}\" if row['num_ciclo'] > 1\n", " else f\"C{row['ano']-1}52\", # Assumindo 52 ciclos por ano\n", " axis=1\n", ")\n", "\n", "# Remover colunas auxiliares se não precisar\n", "df_result = df_result.drop(['ano', 'num_ciclo'], axis=1)\n", "\n", "df_result.head()" ] }, { "cell_type": "code", "execution_count": 5, "id": "6b665272", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_35380\\1986334479.py:26: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", " df_estoque = pd.read_sql(query_estoque, conn)\n", "C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_35380\\1986334479.py:47: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", " df_ruptura = pd.read_sql(query_ruptura, conn)\n" ] } ], "source": [ "conn = pyodbc.connect(\n", " f\"DRIVER={{SQL Server}};\"\n", " f\"SERVER={config['banco']['host']},1433;\"\n", " f\"DATABASE=GINSENG;\"\n", " f\"UID={config['banco']['user']};\"\n", " f\"PWD={config['banco']['password']}\")\n", "\n", "# 1. Puxa estoque zerado (já filtrado)\n", "query_estoque = \"\"\"\n", "SELECT \n", " emh.PDV,\n", " emh.SKU,\n", " cd.Ciclo ,\n", " COUNT(emh.data_estoque) AS QTD_dias_zerado\n", "FROM estoque_mar_historico emh\n", "INNER JOIN (\n", " SELECT DISTINCT bm.PDV\n", " FROM base_pdvs_marca bm\n", " WHERE bm.TRANSFER = 'VD'\n", ") bpm ON emh.PDV = bpm.PDV\n", "inner join ciclos_data_2025 cd on cd.[Date] = emh.data_estoque and cd.MARCA ='BOT'\n", "WHERE emh.[ESTOQUE ATUAL] = 0\n", " AND emh.data_estoque > '2025-07-01'\n", " group by emh.sku, emh.PDV ,cd.Ciclo \n", "\"\"\"\n", "df_estoque = pd.read_sql(query_estoque, conn)\n", "\n", "# 3. Puxa ruptura\n", "query_ruptura = \"\"\"\n", "SELECT \n", " ciclo,\n", " ponto_de_venda,\n", " sku,\n", " descricao,\n", " categoria,\n", " marca,\n", " classe,\n", " fase_do_produto,\n", " valor_da_receita,\n", " valor_da_ruptura,\n", " percentual_da_ruptura,\n", " quantidade_de_ruptura,\n", " macro_causa\n", "FROM ruptura\n", "WHERE ciclo in ('202510','202511','202512','202513','202514','202515','202516','202517')\n", "\"\"\"\n", "df_ruptura = pd.read_sql(query_ruptura, conn)\n", "\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "252fc8dd", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\joao.herculano\\AppData\\Local\\Temp\\ipykernel_35380\\392044023.py:22: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", " df_criticos = pd.read_sql(query_criticos, conn)\n" ] } ], "source": [ "conn = pyodbc.connect(\n", " f\"DRIVER={{SQL Server}};\"\n", " f\"SERVER={config['banco']['host']},1433;\"\n", " f\"DATABASE=GINSENG;\"\n", " f\"UID={config['banco']['user']};\"\n", " f\"PWD={config['banco']['password']}\")\n", "\n", "query_criticos = \"\"\"\n", "select dh.loja_id as PDV, \n", "dh.code as SKU,\n", "c.Ciclo,\n", "count(dh.criticalitem_iscritical) as QTD_Dias_Critico\n", "from draft_historico dh \n", "inner join ciclos_data_2025 c on c.[Date] = dh.[data] and c.MARCA = 'BOT'\n", "where dh.criticalitem_iscritical = 1\n", "group by \n", "dh.loja_id , \n", "dh.code,\n", "c.Ciclo\n", "\"\"\"\n", "\n", "df_criticos = pd.read_sql(query_criticos, conn)" ] }, { "cell_type": "code", "execution_count": 7, "id": "11e35073", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['PDV', 'SKU', 'Ciclo', 'QTD_dias_zerado'], dtype='object')" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_estoque.columns" ] }, { "cell_type": "code", "execution_count": 8, "id": "f1a52151", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
cicloponto_de_vendaskudescricaocategoriamarcaclassefase_do_produtovalor_da_receitavalor_da_rupturapercentual_da_rupturaquantidade_de_rupturamacro_causaPDVSKUCicloQTD_dias_zeradoCiclo_clean
0202510209981004FLORATTA DES COL MY BLUE 75mlPERFUMARIABOTEMaduro0348.561002Causa Indústria209981004C2025108.0202510
1202510242931004FLORATTA DES COL MY BLUE 75mlPERFUMARIABOTBMaduro0173.351001Causa Indústria242931004C2025102.0202510
2202510209681296PMPCK THE BLEND DES ANTIT AER 2x75gDESODORANTESBOTCMaduro084.221001Causa Indústria209681296C20251013.0202510
3202510209691296PMPCK THE BLEND DES ANTIT AER 2x75gDESODORANTESBOTEMaduro052.281000Causa Indústria209691296C20251013.0202510
4202510209701296PMPCK THE BLEND DES ANTIT AER 2x75gDESODORANTESBOTEMaduro093.431001Causa Indústria209701296C20251013.0202510
\n", "
" ], "text/plain": [ " ciclo ponto_de_venda sku descricao \\\n", "0 202510 20998 1004 FLORATTA DES COL MY BLUE 75ml \n", "1 202510 24293 1004 FLORATTA DES COL MY BLUE 75ml \n", "2 202510 20968 1296 PMPCK THE BLEND DES ANTIT AER 2x75g \n", "3 202510 20969 1296 PMPCK THE BLEND DES ANTIT AER 2x75g \n", "4 202510 20970 1296 PMPCK THE BLEND DES ANTIT AER 2x75g \n", "\n", " categoria marca classe fase_do_produto valor_da_receita \\\n", "0 PERFUMARIA BOT E Maduro 0 \n", "1 PERFUMARIA BOT B Maduro 0 \n", "2 DESODORANTES BOT C Maduro 0 \n", "3 DESODORANTES BOT E Maduro 0 \n", "4 DESODORANTES BOT E Maduro 0 \n", "\n", " valor_da_ruptura percentual_da_ruptura quantidade_de_ruptura \\\n", "0 348.56 100 2 \n", "1 173.35 100 1 \n", "2 84.22 100 1 \n", "3 52.28 100 0 \n", "4 93.43 100 1 \n", "\n", " macro_causa PDV SKU Ciclo QTD_dias_zerado Ciclo_clean \n", "0 Causa Indústria 20998 1004 C202510 8.0 202510 \n", "1 Causa Indústria 24293 1004 C202510 2.0 202510 \n", "2 Causa Indústria 20968 1296 C202510 13.0 202510 \n", "3 Causa Indústria 20969 1296 C202510 13.0 202510 \n", "4 Causa Indústria 20970 1296 C202510 13.0 202510 " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "# ---- Ajuste de ciclo ----\n", "# Ciclo de df_estoque está no formato \"Cxxxx\" (tipo C202510 por exemplo)\n", "# No SQL você removia a 1ª letra, aqui fazemos o mesmo:\n", "df_estoque['Ciclo_clean'] = df_estoque['Ciclo'].astype(str).str[1:]\n", "\n", "# ---- Join réplica da query SQL ----\n", "df_final = df_ruptura.merge(\n", " df_estoque,\n", " left_on=[\"sku\", \"ponto_de_venda\", \"ciclo\"],\n", " right_on=[\"SKU\", \"PDV\", \"Ciclo_clean\"],\n", " how=\"left\"\n", ")\n", "\n", "# ---- Ordenar igual ao SQL ----\n", "df_final = df_final.sort_values([\"ciclo\", \"SKU\", \"PDV\"]).reset_index(drop=True)\n", "\n", "df_final.head()" ] }, { "cell_type": "code", "execution_count": 9, "id": "0005aa7e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CicloPDVcod_produtopedido_iddata_emissao_nfdata_pedidodata_prevista_atendimentofaturado_industriaquantidade_pedidastatussalescurvevalor_total_produtosnotaspedidosatendimentociclo_anterior
0C202507125225275715159222025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000535Parcialmente AtendidoC45.363195312701652027060.142857C202506
1C202507128175275715159182025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.00000002490Parcialmente AtendidoC217.713175412201652024910.266667C202506
2C202507128178706615173062025-07-092025-05-22 00:00:00.00000002025-06-13 00:00:00.000000019ConcluídoC6.113175412201652066430.111111C202506
3C202507128185275715159242025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000425Parcialmente AtendidoC36.297607778201652027070.16C202506
4C202507128205275715159432025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000320Parcialmente AtendidoC27.212940384601652023690.15C202506
\n", "
" ], "text/plain": [ " Ciclo PDV cod_produto pedido_id data_emissao_nf \\\n", "0 C202507 12522 52757 1515922 2025-07-09 \n", "1 C202507 12817 52757 1515918 2025-07-09 \n", "2 C202507 12817 87066 1517306 2025-07-09 \n", "3 C202507 12818 52757 1515924 2025-07-09 \n", "4 C202507 12820 52757 1515943 2025-07-09 \n", "\n", " data_pedido data_prevista_atendimento \\\n", "0 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "1 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "2 2025-05-22 00:00:00.0000000 2025-06-13 00:00:00.0000000 \n", "3 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "4 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "\n", " faturado_industria quantidade_pedida status salescurve \\\n", "0 5 35 Parcialmente Atendido C \n", "1 24 90 Parcialmente Atendido C \n", "2 1 9 Concluído C \n", "3 4 25 Parcialmente Atendido C \n", "4 3 20 Parcialmente Atendido C \n", "\n", " valor_total_produtos notas pedidos atendimento ciclo_anterior \n", "0 45.36 31953127 0165202706 0.142857 C202506 \n", "1 217.71 31754122 0165202491 0.266667 C202506 \n", "2 6.11 31754122 0165206643 0.111111 C202506 \n", "3 36.29 76077782 0165202707 0.16 C202506 \n", "4 27.21 29403846 0165202369 0.15 C202506 " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_result.head()" ] }, { "cell_type": "code", "execution_count": 10, "id": "8200c719", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CicloPDVcod_produtopedido_iddata_emissao_nfdata_pedidodata_prevista_atendimentofaturado_industriaquantidade_pedidastatussalescurvevalor_total_produtosnotaspedidosatendimentociclo_anteriorciclo_anterior_tratado
0C202507125225275715159222025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000535Parcialmente AtendidoC45.363195312701652027060.142857C202506202506
1C202507128175275715159182025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.00000002490Parcialmente AtendidoC217.713175412201652024910.266667C202506202506
2C202507128178706615173062025-07-092025-05-22 00:00:00.00000002025-06-13 00:00:00.000000019ConcluídoC6.113175412201652066430.111111C202506202506
3C202507128185275715159242025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000425Parcialmente AtendidoC36.297607778201652027070.16C202506202506
4C202507128205275715159432025-07-092025-05-22 00:00:00.00000002025-06-06 00:00:00.0000000320Parcialmente AtendidoC27.212940384601652023690.15C202506202506
\n", "
" ], "text/plain": [ " Ciclo PDV cod_produto pedido_id data_emissao_nf \\\n", "0 C202507 12522 52757 1515922 2025-07-09 \n", "1 C202507 12817 52757 1515918 2025-07-09 \n", "2 C202507 12817 87066 1517306 2025-07-09 \n", "3 C202507 12818 52757 1515924 2025-07-09 \n", "4 C202507 12820 52757 1515943 2025-07-09 \n", "\n", " data_pedido data_prevista_atendimento \\\n", "0 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "1 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "2 2025-05-22 00:00:00.0000000 2025-06-13 00:00:00.0000000 \n", "3 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "4 2025-05-22 00:00:00.0000000 2025-06-06 00:00:00.0000000 \n", "\n", " faturado_industria quantidade_pedida status salescurve \\\n", "0 5 35 Parcialmente Atendido C \n", "1 24 90 Parcialmente Atendido C \n", "2 1 9 Concluído C \n", "3 4 25 Parcialmente Atendido C \n", "4 3 20 Parcialmente Atendido C \n", "\n", " valor_total_produtos notas pedidos atendimento ciclo_anterior \\\n", "0 45.36 31953127 0165202706 0.142857 C202506 \n", "1 217.71 31754122 0165202491 0.266667 C202506 \n", "2 6.11 31754122 0165206643 0.111111 C202506 \n", "3 36.29 76077782 0165202707 0.16 C202506 \n", "4 27.21 29403846 0165202369 0.15 C202506 \n", "\n", " ciclo_anterior_tratado \n", "0 202506 \n", "1 202506 \n", "2 202506 \n", "3 202506 \n", "4 202506 " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_result['ciclo_anterior_tratado'] = df_result['ciclo_anterior'].str[-6:]\n", "\n", "df_result.head()" ] }, { "cell_type": "code", "execution_count": 11, "id": "415662ba", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(231917, 35)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_contest_rupt = pd.merge(left=df_final,right=df_result,left_on= ['ciclo','ponto_de_venda','sku'],right_on=['ciclo_anterior_tratado','PDV','cod_produto'],how='left')\n", "\n", "df_contest_rupt.shape" ] }, { "cell_type": "code", "execution_count": 12, "id": "a564015b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
PDVSKUCritico no CicloQTD_Dias_Criticoanonum_cicloCritico no Ciclo Anterior
01281780888C20251114202511C202510
12315649970C20251116202511C202510
21252285105C20251311202513C202512
32098949958C2025132202513C202512
42370348785C2025156202515C202514
\n", "
" ], "text/plain": [ " PDV SKU Critico no Ciclo QTD_Dias_Critico ano num_ciclo \\\n", "0 12817 80888 C202511 14 2025 11 \n", "1 23156 49970 C202511 16 2025 11 \n", "2 12522 85105 C202513 11 2025 13 \n", "3 20989 49958 C202513 2 2025 13 \n", "4 23703 48785 C202515 6 2025 15 \n", "\n", " Critico no Ciclo Anterior \n", "0 C202510 \n", "1 C202510 \n", "2 C202512 \n", "3 C202512 \n", "4 C202514 " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "df_criticos['ano'] = df_criticos['Ciclo'].str[1:5].astype(int)\n", "df_criticos['num_ciclo'] = df_criticos['Ciclo'].str[5:].astype(int)\n", "\n", "\n", "df_criticos['ciclo_anterior'] = df_criticos.apply(\n", " lambda row: f\"C{row['ano']}{row['num_ciclo']-1:02d}\" if row['num_ciclo'] > 1\n", " else f\"C{row['ano']-1}52\", # Assumindo 52 ciclos por ano\n", " axis=1\n", ")\n", "\n", "df_criticos = df_criticos.rename(columns={'Ciclo':'Critico no Ciclo','ciclo_anterior':'Critico no Ciclo Anterior' })\n", "\n", "df_criticos.head()" ] }, { "cell_type": "code", "execution_count": 13, "id": "9bdb3fb2", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt['ciclo'] = \"C\"+df_contest_rupt['ciclo']" ] }, { "cell_type": "code", "execution_count": 14, "id": "30c5e102", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit = pd.merge(df_contest_rupt,df_criticos[['PDV','SKU','Critico no Ciclo']],\n", " left_on=['ponto_de_venda','sku','ciclo'],\n", " right_on=['PDV','SKU','Critico no Ciclo'],\n", " how='left')\n", "\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "74e983cd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['ciclo', 'ponto_de_venda', 'sku', 'descricao', 'categoria', 'marca',\n", " 'classe', 'fase_do_produto', 'valor_da_receita', 'valor_da_ruptura',\n", " 'percentual_da_ruptura', 'quantidade_de_ruptura', 'macro_causa',\n", " 'QTD_dias_zerado', 'pedido_id', 'data_emissao_nf', 'data_pedido',\n", " 'data_prevista_atendimento', 'faturado_industria', 'quantidade_pedida',\n", " 'valor_total_produtos', 'notas', 'pedidos', 'atendimento',\n", " 'ciclo_anterior', 'ciclo_anterior_tratado', 'Critico no Ciclo'],\n", " dtype='object')" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_contest_rupt_crit = df_contest_rupt_crit.drop(columns=['PDV_x', 'SKU_x', 'Ciclo_x','Ciclo_clean',\n", " 'Ciclo_y', 'PDV_y', 'cod_produto','status', 'salescurve','PDV', 'SKU_y'])\n", "\n", "df_contest_rupt_crit.columns" ] }, { "cell_type": "code", "execution_count": 16, "id": "4a660875", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit = pd.merge(df_contest_rupt_crit,df_criticos[['PDV','SKU','Critico no Ciclo Anterior']],\n", " left_on=['ponto_de_venda','sku','ciclo'],\n", " right_on=['PDV','SKU','Critico no Ciclo Anterior'],\n", " how='left')" ] }, { "cell_type": "code", "execution_count": 17, "id": "b8522eb4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
cicloponto_de_vendaskudescricaocategoriamarcaclassefase_do_produtovalor_da_receitavalor_da_ruptura...valor_total_produtosnotaspedidosatendimentociclo_anteriorciclo_anterior_tratadoCritico no CicloPDVSKUCritico no Ciclo Anterior
0CC202510209981004FLORATTA DES COL MY BLUE 75mlPERFUMARIABOTEMaduro0348.56...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1CC202510242931004FLORATTA DES COL MY BLUE 75mlPERFUMARIABOTBMaduro0173.35...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2CC202510209681296PMPCK THE BLEND DES ANTIT AER 2x75gDESODORANTESBOTCMaduro084.22...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3CC202510209691296PMPCK THE BLEND DES ANTIT AER 2x75gDESODORANTESBOTEMaduro052.28...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4CC202510209701296PMPCK THE BLEND DES ANTIT AER 2x75gDESODORANTESBOTEMaduro093.43...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", "

5 rows × 30 columns

\n", "
" ], "text/plain": [ " ciclo ponto_de_venda sku descricao \\\n", "0 CC202510 20998 1004 FLORATTA DES COL MY BLUE 75ml \n", "1 CC202510 24293 1004 FLORATTA DES COL MY BLUE 75ml \n", "2 CC202510 20968 1296 PMPCK THE BLEND DES ANTIT AER 2x75g \n", "3 CC202510 20969 1296 PMPCK THE BLEND DES ANTIT AER 2x75g \n", "4 CC202510 20970 1296 PMPCK THE BLEND DES ANTIT AER 2x75g \n", "\n", " categoria marca classe fase_do_produto valor_da_receita \\\n", "0 PERFUMARIA BOT E Maduro 0 \n", "1 PERFUMARIA BOT B Maduro 0 \n", "2 DESODORANTES BOT C Maduro 0 \n", "3 DESODORANTES BOT E Maduro 0 \n", "4 DESODORANTES BOT E Maduro 0 \n", "\n", " valor_da_ruptura ... valor_total_produtos notas pedidos atendimento \\\n", "0 348.56 ... NaN NaN NaN NaN \n", "1 173.35 ... NaN NaN NaN NaN \n", "2 84.22 ... NaN NaN NaN NaN \n", "3 52.28 ... NaN NaN NaN NaN \n", "4 93.43 ... NaN NaN NaN NaN \n", "\n", " ciclo_anterior ciclo_anterior_tratado Critico no Ciclo PDV SKU \\\n", "0 NaN NaN NaN NaN NaN \n", "1 NaN NaN NaN NaN NaN \n", "2 NaN NaN NaN NaN NaN \n", "3 NaN NaN NaN NaN NaN \n", "4 NaN NaN NaN NaN NaN \n", "\n", " Critico no Ciclo Anterior \n", "0 NaN \n", "1 NaN \n", "2 NaN \n", "3 NaN \n", "4 NaN \n", "\n", "[5 rows x 30 columns]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_contest_rupt_crit['ciclo'] = \"C\"+df_contest_rupt_crit['ciclo']\n", "\n", "df_contest_rupt_crit.head()" ] }, { "cell_type": "code", "execution_count": 18, "id": "cac20389", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit = df_contest_rupt_crit.drop(columns=['PDV',\n", " 'SKU','ciclo_anterior', 'ciclo_anterior_tratado'])" ] }, { "cell_type": "code", "execution_count": 19, "id": "aa593330", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit['QTD_dias_zerado'] = df_contest_rupt_crit['QTD_dias_zerado'].fillna(0)" ] }, { "cell_type": "code", "execution_count": null, "id": "e2c6ae0c", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit['causa_rpt_revisada'] = np.where((df_contest_rupt_crit['valor_da_ruptura']==0)| (df_contest_rupt_crit['QTD_dias_zerado']== 0),\"Não Houve Ruptura\",np.where(df_contest_rupt_crit['atendimento']< 0.86,\"Causa Indústria\", np.where(df_contest_rupt_crit['fase_do_produto'] == \"Lançamento\",\"Lançamento\",\"Causa Franqueado\")))" ] }, { "cell_type": "code", "execution_count": 21, "id": "115a4645", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit['causa_rpt_revisada'] = np.where(df_contest_rupt_crit['macro_causa']==\"Causa Franqueado\",df_contest_rupt_crit['causa_rpt_revisada'],df_contest_rupt_crit['macro_causa'])" ] }, { "cell_type": "code", "execution_count": 22, "id": "199addf1", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit['valor_da_ruptura'] = df_contest_rupt_crit['valor_da_ruptura'].str.replace(',','.')\n", "\n", "df_contest_rupt_crit['valor_da_ruptura'] = df_contest_rupt_crit['valor_da_ruptura'].astype('float')" ] }, { "cell_type": "code", "execution_count": 23, "id": "477c301b", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit['valor_da_receita'] = df_contest_rupt_crit['valor_da_receita'].str.replace(',','.')\n", "\n", "df_contest_rupt_crit['valor_da_receita'] = df_contest_rupt_crit['valor_da_receita'].astype('float')" ] }, { "cell_type": "code", "execution_count": 24, "id": "5085cf12", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit['VALOR RPT FRANQ'] = np.where(df_contest_rupt_crit['macro_causa']==\"Causa Franqueado\", df_contest_rupt_crit['valor_da_ruptura'],0)\n", "\n", "df_contest_rupt_crit['valor rpt franq revisada'] = np.where(df_contest_rupt_crit['causa_rpt_revisada']==\"Causa Franqueado\", df_contest_rupt_crit['valor_da_ruptura'],0)" ] }, { "cell_type": "code", "execution_count": 25, "id": "9b2a7019", "metadata": {}, "outputs": [], "source": [ "df_contest_rupt_crit.to_excel(r\"C:\\Users\\joao.herculano\\Documents\\test_rpt_ajustado24-10.xlsx\",index=False)" ] }, { "cell_type": "code", "execution_count": null, "id": "f19b9b59", "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 }