diff --git a/src/pages/tableau.py b/src/pages/tableau.py index 09a6aad..02339d3 100644 --- a/src/pages/tableau.py +++ b/src/pages/tableau.py @@ -5,7 +5,6 @@ import uuid from datetime import datetime import dash_bootstrap_components as dbc -import polars as pl from dash import ( ClientsideFunction, Input, @@ -20,7 +19,7 @@ from dash import ( ) from flask_login import current_user -from src.db import query_marches, schema +from src.db import schema from src.figures import ag_grid, make_column_picker from src.pages._compte_shell import current_user_has_subscription from src.saved_views import db as saved_views_db @@ -31,10 +30,8 @@ from src.utils.seo import META_CONTENT from src.utils.table import ( COLUMNS, build_view_query, - filter_table_data, get_default_hidden_columns, invert_columns, - sort_table_data, write_styled_excel, ) from src.utils.tracking import track_search @@ -467,27 +464,25 @@ def update_meta(total): @callback( Output("download-data", "data"), Input("btn-download-data", "n_clicks"), - State("tableau_datatable", "filter_query"), - State("tableau_datatable", "sort_by"), - State("tableau_datatable", "hidden_columns"), + State("tableau_grid", "filterModel"), + State("tableau_grid", "columnState"), prevent_initial_call=True, ) -def download_data(n_clicks, filter_query, sort_by, hidden_columns: list | None = None): - lff: pl.LazyFrame = query_marches().lazy() +def download_data(n_clicks, filter_model, column_state): + from src.utils.grid import export_dataframe - # Les colonnes masquées sont supprimées - if hidden_columns: - lff = lff.drop(hidden_columns) - - if filter_query: - track_search(filter_query, "tab download") - lff = filter_table_data(lff, filter_query) - - if sort_by and len(sort_by) > 0: - lff = sort_table_data(lff, sort_by) + sort_model = [ + {"colId": c["colId"], "sort": c["sort"]} + for c in (column_state or []) + if c.get("sort") + ] + hidden_columns = [c["colId"] for c in (column_state or []) if c.get("hide")] + if filter_model: + track_search(json.dumps(filter_model), "tab download") + df = export_dataframe(filter_model, sort_model, hidden_columns) def to_bytes(buffer): - write_styled_excel(lff.collect(engine="streaming"), buffer) + write_styled_excel(df, buffer) date = datetime.now().strftime("%Y-%m-%d_%H:%M:%S") return dcc.send_bytes(to_bytes, filename=f"decp_{date}.xlsx") diff --git a/src/utils/grid.py b/src/utils/grid.py index f175b97..c3e125b 100644 --- a/src/utils/grid.py +++ b/src/utils/grid.py @@ -37,6 +37,23 @@ def fetch_grid_page( return page.to_dicts(), total +def export_dataframe(filter_model, sort_model, hidden_columns) -> pl.DataFrame: + """Renvoie les lignes filtrées/triées pour l'export Excel. + + Colonnes masquées exclues, valeurs brutes (non post-traitées HTML). + """ + ast = filtermodel_to_ast(filter_model, schema) + filter_sql, params = ast_to_sql(ast, schema) + order_by = sort_model_to_sql(sort_model, schema) or None + visible = [c for c in schema.names() if c not in set(hidden_columns or [])] + return query_marches( + where_sql=filter_sql, + params=params, + columns=visible, + order_by=order_by, + ) + + _LINK_COLUMNS = { "marche", "uid", diff --git a/tests/test_grid.py b/tests/test_grid.py index 9d603ac..8303966 100644 --- a/tests/test_grid.py +++ b/tests/test_grid.py @@ -1,4 +1,4 @@ -from src.utils.grid import fetch_grid_page, grid_column_defs +from src.utils.grid import export_dataframe, fetch_grid_page, grid_column_defs def test_column_defs_have_field_and_filter(): @@ -40,3 +40,14 @@ def test_fetch_grid_page_filter_reduces_count(): def test_fetch_grid_page_offset_slicing(): rows, _ = fetch_grid_page(None, None, 0, 5) assert len(rows) <= 5 + + +def test_export_dataframe_excludes_hidden_columns(): + df = export_dataframe(None, None, hidden_columns=["objet"]) + assert "objet" not in df.columns + + +def test_export_dataframe_applies_filter(): + fm = {"objet": {"filterType": "text", "type": "contains", "filter": "zzzzzznope"}} + df = export_dataframe(fm, None, hidden_columns=[]) + assert df.height == 0 diff --git a/tests/test_main.py b/tests/test_main.py index b458dc3..0c9f1b9 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -99,7 +99,7 @@ def test_003_tableau_download(dash_duo: DashComposite): print(app.server.name) outputs = [ - download_data(1, "", [], None), + download_data(1, None, None), download_acheteur_data(1, "/acheteurs/123", "2025", "ACHETEUR 1"), download_titulaire_data(1, "/titulaires/345", "2025", "TITULAIRE 1"), ]