Something like this will need to be your df file:
# from multiprocessing.util import is_exiting
from ntpath import join
from peewee import fn, JOIN
from models import Detalhe, Produto, Grupo, Familia, Unidade, Pessoas, Estoque, Codigos, Docitem, Comitem, Documen
import pandas as pd
from datetime import datetime
def df_dados_gerais_func():
''' ABAIXO CRIO MINHA CONSULTA PARA USAR NOS GRÁFICOS '''
# -------------------------------------------------------------------------------------------------------------
# Usarei as consultas 'subquery' e 'estoque' abaixo para unir com a consulta 'dados_gerais'
EstoqueAlias = Estoque.alias() # Faco referencia a tabela Estoque
# Criamos uma subconsulta para listar o alor máximo para cada iddetalhe, ou seja, sempre o último
subquery_estoque = (EstoqueAlias
.select(
EstoqueAlias.iddetalhe,
fn.MAX(EstoqueAlias.dtreferencia).alias('max_ts'))
.group_by(EstoqueAlias.iddetalhe)
.alias('post_max_subquery'))
# Consulta que unifica a subquery acima com estoque abaixo:
estoque = (Estoque
.select(
Estoque.qtestoque2,
Estoque.qtestoque,
Estoque.iddetalhe,
)
.switch(Estoque)
.join(subquery_estoque, on=(
(Estoque.dtreferencia == subquery_estoque.c.max_ts) &
(Estoque.iddetalhe == subquery_estoque.c.iddetalhe))))
# -------------------------------------------------------------------------------------------------------------
df_estoque_completo = pd.DataFrame(list(estoque.dicts()))
df_estoque = pd.DataFrame()
df_estoque['iddetalhe'] = df_estoque_completo.iddetalhe
df_estoque['qtestoque'] = df_estoque_completo.qtestoque
df_estoque['qtestoque2'] = df_estoque_completo.qtestoque2
# -------------------------------------------------------------------------------------------------------------
# Crio um dataframecom pessoas
pessoas = (Pessoas(Pessoas.idpessoa, Pessoas.nmpessoa).select())
df_pessoa_completo = pd.DataFrame(list(pessoas.dicts()))
df_pessoa = pd.DataFrame()
df_pessoa['idpessoa'] = df_pessoa_completo.idpessoa
df_pessoa['nmpessoa'] = df_pessoa_completo.nmpessoa
df_pessoa['nmendereco'] = df_pessoa_completo.nmendereco
df_pessoa['nmbairro'] = df_pessoa_completo.nmbairro
df_pessoa['nmcidade'] = df_pessoa_completo.nmcidade
df_pessoa['iduf'] = df_pessoa_completo.iduf
# Base de dados relacionada inteiramente com LEFT_OUTER, ou seja, mostra os dados do produto e se tiver movimento ele lista.
# sem a quantidade em estoque
# .limit(10) *** LIMITA QUANTIDADE DE LINHAS
dados_gerais = (Detalhe().select(
Detalhe.iddetalhe, Detalhe.cdprincipal, Detalhe.dsdetalhe, Detalhe.vlprecocusto, Detalhe.vlprecovenda,
Docitem.iddocumento, Docitem.dtreferencia, Docitem.qtitem, Docitem.tpoperacao, Docitem.tpdevolucao,
Docitem.vlunitario, Docitem.vldesconto,
Documen.idpessoa.alias('idcliente'), Documen.stdocumentocancelado, Documen.nrdocumento,
Documen.vldesconto.alias('desconto_global'),
Familia.dsfamilia,
Grupo.nmgrupo,
Unidade.dsunidade,
Comitem.idpessoa.alias('idvendedor'), Comitem.vlbasecomissao, Comitem.alcomissao).
join(Produto, JOIN.LEFT_OUTER, on=(Detalhe.idproduto == Produto.idproduto)).
join(Unidade, JOIN.LEFT_OUTER, on=(Produto.idunidade == Unidade.idunidade)).
join(Grupo, JOIN.LEFT_OUTER, on=(Produto.idgrupo == Grupo.idgrupo)).
join(Familia, JOIN.LEFT_OUTER, on=(Detalhe.idfamilia == Familia.idfamilia)).
join(Docitem, JOIN.LEFT_OUTER, on=(Detalhe.iddetalhe == Docitem.iddetalhe)).
join(Documen, JOIN.LEFT_OUTER, on=(Docitem.iddocumento == Documen.iddocumento)).
join(Comitem, JOIN.LEFT_OUTER, on=(Docitem.iddocumentoitem == Comitem.iddocitem))
)
# Transformando uma consulta peewee em uma lista, consequentemente em um datagrame do pandas.
df_dados_gerais = pd.DataFrame(
list(dados_gerais.dicts()))
# Unificando df_dados_gerais e df_estoque pelo campo 'iddetalhe' comum em ambos
df_dados_gerais = pd.merge(df_dados_gerais, df_estoque, on='iddetalhe', how='left')
# **************************** TENTAR USAR CONCAT EM TUDO E DESCOBRIR VALOR UNITARIO EM COCITEM ****************************
df_dados_gerais = pd.merge(df_dados_gerais, df_pessoa, left_on='idcliente', right_on='idpessoa', how='left')
df_dados_gerais = pd.merge(df_dados_gerais, df_pessoa, left_on='idvendedor', right_on='idpessoa', how='left')
df_dados_gerais = df_dados_gerais.drop(columns=['iddetalhe', 'iddocumento', 'idcliente', 'idvendedor', 'idpessoa_x'])
df_dados_gerais = df_dados_gerais.drop(columns=['iduf_y', 'nmendereco_y', 'nmbairro_y', 'nmcidade_y', 'idpessoa_y'])
df_dados_gerais.rename(columns={'nmpessoa_y': 'VENDEDOR',
'nmpessoa_x': 'CLIENTE_FORNECEDOR',
'iduf_x': 'UF',
'nmendereco_x': 'LOGRADOURO',
'nmbairro_x': 'BAIRRO',
'nmcidade_x': 'CIDADE',
'qtitem': 'QUANTIDADE',
'dtreferencia': 'DTREFERENCIA',
'vlprecovenda': 'VENDA',
'vlprecocusto': 'CUSTO',
'dsdetalhe': 'DESCRICAO',
'cdprincipal': 'CODIGO',
'tpdevolucao': 'DEVOLUCAO',
'tpoperacao': 'OPERACAO',
'stdocumentocancelado': 'CANCELADO',
'dsfamilia': 'FAMILIA',
'nmgrupo': 'GRUPO',
'dsunidade': 'UNIDADE',
'qtestoque': 'PRATELEIRA',
'qtestoque2': 'DEPOSITO',
'nrdocumento': 'NRDOCUMENTO',
'vlbasecomissao': 'VLBASECOMISSAO',
'alcomissao': 'ALCOMISSAO',
'vldesconto': 'DESCONTO_ITEM',
'desconto_global': 'DESCONTO_GLOBAL'}, inplace=True)
# df_dados_gerais.to_excel('C:/Users/EliasPai/Desktop/confere.xlsx')
# Verificando nome das colunas para renomear.
# df_dados_gerais.info()
# Renomeando cada coluna.
df_dados_gerais.columns = ['CODIGO', 'DESCRICAO', 'CUSTO', 'VENDA', 'DTREFERENCIA', 'QUANTIDADE', 'OPERACAO',
'DEVOLUCAO', 'VLUNITARIO', 'DESCONTO_ITEM', 'CANCELADO', 'NUMERO',
'DESCONTO_GLOBAL', 'FAMILIA', 'GRUPO', 'UNIDADE', 'VLBASECOMISSAO', 'ALCOMISSAO',
'QT_PRATELEIRA', 'QT_DEPOSITO', 'CLIENTE_FORNECEDOR', 'LOGRADOURO',
'BAIRRO', 'CIDADE', 'UF', 'VENDEDOR']
# -------------------------------------------------------------------------------------------------------------
# **** PREENCHENDO COLUNAS ****
# Aplicando valores a campos em branco ou com valores que não deveriam aparecer (Incluo ou substituo)
df_dados_gerais['OPERACAO'] = df_dados_gerais['OPERACAO'].fillna('X')
df_dados_gerais['FAMILIA'] = df_dados_gerais['FAMILIA'].fillna('NAO_PREENCHIDO')
df_dados_gerais['CLIENTE_FORNECEDOR'] = df_dados_gerais['CLIENTE_FORNECEDOR'].fillna('NAO_PREENCHIDO')
# Erro linha de cima.
df_dados_gerais['DTREFERENCIA'] = df_dados_gerais['DTREFERENCIA'].fillna('1900-01-01 00:00:01')
df_dados_gerais['CODIGO'] = df_dados_gerais['CODIGO'].fillna('000000')
df_dados_gerais['DESCRICAO'] = df_dados_gerais['DESCRICAO'].fillna('DESCONSIDERE')
df_dados_gerais['QUANTIDADE'] = df_dados_gerais['QUANTIDADE'].fillna(0)
df_dados_gerais['CUSTO'] = df_dados_gerais['CUSTO'].fillna(0)
df_dados_gerais['VENDA'] = df_dados_gerais['VENDA'].fillna(0)
# df_dados_gerais['ATIVO'] = df_dados_gerais['ATIVO'].fillna('N')
df_dados_gerais['GRUPO'] = df_dados_gerais['GRUPO'].fillna('NAO_PREENCHIDO')
df_dados_gerais['UNIDADE'] = df_dados_gerais['UNIDADE'].fillna('NAO_PREENCHIDO')
df_dados_gerais['QT_PRATELEIRA'] = df_dados_gerais['QT_PRATELEIRA'].fillna(0)
df_dados_gerais['QT_DEPOSITO'] = df_dados_gerais['QT_DEPOSITO'].fillna(0)
df_dados_gerais['VENDEDOR'] = df_dados_gerais['VENDEDOR'].fillna('NAO_PREENCHIDO')
df_dados_gerais['LOGRADOURO'] = df_dados_gerais['LOGRADOURO'].fillna('NAO_PREENCHIDO')
df_dados_gerais['BAIRRO'] = df_dados_gerais['BAIRRO'].fillna('NAO_PREENCHIDO')
df_dados_gerais['CIDADE'] = df_dados_gerais['CIDADE'].fillna('NAO_PREENCHIDO')
df_dados_gerais['UF'] = df_dados_gerais['UF'].fillna('NAO_PREENCHIDO')
df_dados_gerais['DESCONTO_ITEM'] = df_dados_gerais['DESCONTO_ITEM'].fillna(0)
df_dados_gerais['DESCONTO_GLOBAL'] = df_dados_gerais['DESCONTO_GLOBAL'].fillna(0)
# -------------------------------------------------------------------------------------------------------------
# Crio a coluna 'ANO' para filtros futuros.
df_dados_gerais['ANO'] = pd.DatetimeIndex(df_dados_gerais.DTREFERENCIA).year
# Crio uma nova coluna 'MES' e faço a tradução simultanea.
df_dados_gerais['MES'] = pd.DatetimeIndex(df_dados_gerais.DTREFERENCIA).month
# Renomeio novamente as colunas.
df_dados_gerais.columns = ['CODIGO', 'DESCRICAO', 'CUSTO', 'VENDA', 'DTREFERENCIA', 'QUANTIDADE', 'OPERACAO',
'DEVOLUCAO',
'VLUNITARIO', 'DESCONTO_ITEM', 'CANCELADO', 'NUMERO', 'DESCONTO_GLOBAL', 'FAMILIA', 'GRUPO',
'UNIDADE', 'VLBASECOMISSAO', 'ALCOMISSAO',
'QT_PRATELEIRA', 'QT_DEPOSITO', 'CLIENTE_FORNECEDOR', 'LOGRADOURO', 'BAIRRO', 'CIDADE', 'UF',
'VENDEDOR',
'ANO', 'MES']
# Removo dos meus dados toda linha que o código for igual a 000000
df_dados_gerais = df_dados_gerais[df_dados_gerais['CODIGO'] != '000000']
# Faço um cálculo com algumas colunas e crio uma nova 'TOTAL_OPERACAO' e 'ESTOQUE' com o resultado..
df_dados_gerais['TOTAL_OPERACAO'] = (df_dados_gerais['VLUNITARIO'] * df_dados_gerais['QUANTIDADE']) - df_dados_gerais[
'DESCONTO_ITEM']
df_dados_gerais['ESTOQUE'] = df_dados_gerais['QT_DEPOSITO'] + df_dados_gerais['QT_PRATELEIRA']
df_dados_gerais['VLBASECOMISSAO'] = df_dados_gerais['VLBASECOMISSAO'].fillna(df_dados_gerais['TOTAL_OPERACAO'])
# Todas as cidades para maiúsculo.
df_dados_gerais['CIDADE'] = df_dados_gerais['CIDADE'].str.upper()
df_dados_gerais['CIDADE'] = df_dados_gerais['CIDADE'].str.normalize('NFKD').str.encode('ascii',
errors='ignore').str.decode(
'utf-8')
df_dados_gerais.sort_values(by='DTREFERENCIA', ascending=False, inplace=True)
# df_dados_gerais.to_excel('C:/Users/EliasPai/Desktop/df_dados_gerais.xlsx')
return df_dados_gerais
Then in your app, this should work:
from datetime import date
import plotly.graph_objs as go
import dash
from dash import html, dcc, Input, Output, State, dash_table
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
from dash_bootstrap_templates import ThemeSwitchAIO
# Importei meu dataframe do arquivo movimento_geral.py
from movimento_geral import df_dados_gerais_func
# Formatação das tabelas
formatted = {'specifier': ',.2f', 'locale': {'group': '.', 'decimal': ',', }}
# ================================================================== #
from flask import Flask
dbc_css = "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates/dbc.min.css"
server = Flask(__name__)
app = dash.Dash(__name__, server=server, suppress_callback_exceptions=True,
external_stylesheets=[dbc.themes.BOOTSTRAP, dbc_css])
# ============================Styles================================ #
tab_card = {'height': '100%'}
main_config = {
'hovermode': 'x unified',
'legend': {
'yanchor': 'top',
'y': 0.9,
'xanchor': 'left',
'x': 0.1,
'title': {'text': None},
'font': {'color': 'white'},
'bgcolor': 'rgba(0,0,0,0.0)'},
'margin': {'l': 0, 'r': 0, 't': 20, 'b': 0}
}
template_theme1 = 'cyborg'
template_theme2 = 'spacelab'
url_theme1 = dbc.themes.CYBORG
url_theme2 = dbc.themes.SPACELAB
# To dict - Para salvar no dcc.store
df_dados_gerais = df_dados_gerais_func()
df_store = df_dados_gerais.to_dict()
app.layout = dbc.Container([
dcc.Store(id='store-data', data=[], storage_type='memory'),
dcc.Interval(
id='interval-component',
interval=10 * 1000, # in milliseconds
n_intervals=0
),
dbc.Row([
dbc.Col([
dash_table.DataTable(
id='datatable-data',
editable=True,
fixed_rows={'headers': True},
style_cell_conditional=[
{
'if': {'column_id': 'CODIGO'},
'textAlign': 'left'
},
{
'if': {'column_id': 'CODIGO'},
'width': '80px'
},
{
'if': {'column_id': 'ESTOQUE'},
'width': '130px'
},
{
'if': {'column_id': 'UNIDADE'},
'width': '80px'
},
{
'if': {'column_id': 'DESCRICAO'},
'textAlign': 'left', 'width': '230px'
},
{
'if': {'column_id': 'GRUPO'},
'textAlign': 'left'
},
{
'if': {'column_id': 'FAMILIA'},
'textAlign': 'left'
},
{
'if': {'column_id': 'UNIDADE'},
'textAlign': 'left'
},
],
style_data={
'color': 'black',
'backgroundColor': 'white'
},
style_data_conditional=[
{
'if': {'row_index': 'odd'},
'backgroundColor': 'rgb(220, 220, 220)',
}
],
# 'backgroundColor': 'white',
style_header={'textAlign': 'center',
'backgroundColor': 'rgb(210, 210, 210)',
'color': 'black',
'fontWeight': 'bold'},
style_table={'height': '1000px', 'overflowY': 'auto'},
filter_action='native',
sort_action="native",
page_size=1000,
)
], sm=12, lg=12)
], className='g-2 my-auto', style={'margin-top': '7px'})
], fluid=True, style={'height': '100vh'})
# ======== Callbacks ========== #
# Na aba TABELAS, conteúdo da tabela.
@app.callback(
Output('datatable-data', 'data'),
Output('datatable-data', 'columns'),
Input('store-data', 'data')
)
def update_table(d):
print('---------------------- DATA update_table n ----------------------')
print(d)
mask = (df_dados_gerais['ANO'] == 2022) & (df_dados_gerais['OPERACAO'] == 'V') & \
(df_dados_gerais['MES'].isin(11)) & (df_dados_gerais['CANCELADO'] != '*')
print('---------------------- update_table MASK ----------------------')
print(mask)
df_pivot = pd.pivot_table(
df_dados_gerais.loc[mask], index=['CODIGO', 'DESCRICAO',
'ESTOQUE', 'GRUPO',
'FAMILIA', 'UNIDADE', ],
values='QUANTIDADE',
columns='MES',
aggfunc=sum).reset_index().fillna(0)
df_pivot = df_pivot.rename(
{1: 'JAN', 2: 'FEV', 3: 'MAR', 4: 'ABR', 5: 'MAI', 6: 'JUN',
7: 'JUL', 8: 'AGO', 9: 'SET', 10: 'OUT', 11: 'NOV', 12: 'DEZ'}, axis=1)
cols = []
textCols = ['CODIGO', 'DESCRICAO', 'GRUPO', 'FAMILIA', 'UNIDADE']
for i in df_pivot.columns:
if i not in textCols:
cols.append({"name": str(i),
"id": str(i),
"type": "numeric",
"format": formatted})
else:
cols.append({"name": str(i),
"id": str(i),
"type": "text"})
return df_pivot.to_dict('records'), cols
# Load data from PostgreSQL, you have to change database name, user and password.
@app.callback(Output('store-data', 'data'),
Input('interval-component', 'n_intervals'))
def update_data(n_intervals):
print(f'---------------------- FUNÇÃO update_data {n_intervals} ----------------------')
# print(df_dados_gerais.to_dict())
df_dados_gerais = df_dados_gerais_func()
return df_dados_gerais.to_dict()
if __name__ == '__main__':
app.run_server(debug=True)