Hi @adamschroeder, below is the current code.
import dash
from dash import dcc, html, Input, Output, State
import dash_ag_grid as ag
import pandas as pd
import pyodbc
import os
from datetime import datetime, timedelta
from django_plotly_dash import DjangoDash
app = DjangoDash('plant_processing_date_range', add_bootstrap_links=True)
def get_data(productionStartDate, productionEndDate):
conn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};'
f'SERVER={os.getenv("INNOVA_SERVER")};'
'DATABASE=ClearView;'
f'UID={os.getenv("CLEARVIEW_SQL_USER")};'
f'PWD={os.getenv("CLEARVIEW_SQL_PASSWORD")}')
query = f"EXEC sp_cv_SelectPlantProcessingReportDateRange @productionStartDate='{productionStartDate}', @productionEndDate='{productionEndDate}'"
df = pd.read_sql(query, conn)
custom_sort_order_category = {
"Fresh Branded": 1,
"Fresh Private Label": 2,
"Fresh Prvt Label Red/Golden": 3,
"Fresh Outsourced": 4,
"Frozen Branded": 5,
"Frozen Prvt Label Red/Golden": 6,
"Fresh Grade 2": 7,
"Frozen Grade 2": 8,
"Bulk": 9,
}
df['sorting_key_category'] = df['cvProductCategory'].map(custom_sort_order_category)
df = df.sort_values(by=['sorting_key_category', 'cvProductStyle'])
df['sorting_key_style'] = df.groupby('cvProductCategory').cumcount()
return df
def calculate_totals(data):
sum_values = data[["totalPounds", "totalCases"]] if "totalPounds" in data.columns and "totalCases" in data.columns else data
return {
"cvProductCategory": "Total",
"inMaterialCode": "",
"cvProductDescription": "",
"cvPackStyle": "",
"totalPounds": sum_values["totalPounds"].sum() if "totalPounds" in sum_values.columns else 0,
"totalCases": sum_values["totalCases"].sum() if "totalCases" in sum_values.columns else 0,
"cvProductStyle": "",
}
app.layout = html.Div(
[
html.H1("Plant Processing Report by Date Range"),
html.Hr(),
dcc.Store(id="plant-processing-data"),
html.Div([
dcc.DatePickerRange(
id='date-range-picker',
display_format='MM/DD/YYYY',
start_date=(datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d'),
end_date=datetime.now().strftime('%Y-%m-%d'),
),
], style={'margin-bottom': '20px'}), # Apply margin to this div
html.Div([
ag.AgGrid(
id="plant-processing-grid",
style={"height": '80vh'},
enableEnterpriseModules=True,
rowData=None,
defaultColDef={"flex": 1},
columnDefs=[
{"headerName": "Product Category", "field": "cvProductCategory", "sortable": True, "filter": True},
{"headerName": "Item #", "field": "inMaterialCode", "sortable": True, "filter": True},
{"headerName": "Description", "field": "cvProductDescription", "sortable": True, "filter": True},
{"headerName": "Pack Size", "field": "cvPackStyle", "sortable": True, "filter": True},
{"headerName": "Total Pounds", "field": "totalPounds", "sortable": True, "filter": True},
{"headerName": "Total Cases", "field": "totalCases", "sortable": True, "filter": True},
{"headerName": "Product Style", "field": "cvProductStyle", "sortable": True, "filter": True},
],
# Add the pinnedBottomRowData attribute
dashGridOptions={'pinnedBottomRowData': [calculate_totals(pd.DataFrame())]},
),
], style={'margin-top': '20px'}), # Apply margin to this div
]
)
@app.callback([Output("plant-processing-grid", "rowData"),
Output("plant-processing-grid", "pinnedBottomRowData")],
[Input('date-range-picker', 'start_date'),
Input('date-range-picker', 'end_date'),
Input('plant-processing-grid', 'filterModel')])
def update_grid(start_date, end_date, filter_model):
productionStartDate = start_date.replace('-', '')
productionEndDate = end_date.replace('-', '')
data = get_data(productionStartDate, productionEndDate)
if filter_model:
for column, filter_options in filter_model.items():
values = filter_options.get('values', [])
if values:
data = data[data[column].isin(values)]
total_cases = data['totalCases'].sum()
total_pounds = data['totalPounds'].sum()
pinned_bottom_data = [{"cvProductCategory": "Total", "totalCases": total_cases, "totalPounds": total_pounds}]
grid_data = data.to_dict("records")
return grid_data, pinned_bottom_data
if __name__ == '__main__':
app.run_server(debug=True)
And here’s some sample output that it pulls from our server:
inMaterialCode |
cvProductDescription |
cvProductCategory |
cvProductStyle |
cvPackStyle |
totalCases |
totalPounds |
46241 |
FZN BONED 11-13 OZ USA |
Frozen Branded |
Boned |
1/10# FZN IQF BOX |
4 |
40 |
14248 |
FRSH BONED 8 OZ (7-9 OZ) |
Fresh Branded |
Boned |
2/10# FRESH DYNO |
5 |
100 |
Appreciate you looking at this!