Last version of 28/03/2026

This commit is contained in:
2026-03-28 08:17:20 +01:00
parent 82d4860e86
commit 436fddf554
5 changed files with 89 additions and 9 deletions

View File

@@ -1525,9 +1525,9 @@ def main():
console.print("[green]✓ Data saved to JSON files[/green]") console.print("[green]✓ Data saved to JSON files[/green]")
print() print()
# === EXCEL EXPORT === (temporarily disabled for JSON generation testing) # === EXCEL EXPORT ===
# run_normal_mode_export(excel_export_enabled, excel_export_config, run_normal_mode_export(excel_export_enabled, excel_export_config,
# requests_mapping_config, organizations_mapping_config) requests_mapping_config, organizations_mapping_config)
except IOError as io_err: except IOError as io_err:
logging.critical(f"Error while writing JSON file : {io_err}") logging.critical(f"Error while writing JSON file : {io_err}")

View File

@@ -75,7 +75,7 @@ API_AUTH_CONFIG_TOKEN_ENDPOINT = "/api/auth/config-token"
API_AUTH_REFRESH_TOKEN_ENDPOINT = "/api/auth/refreshToken" API_AUTH_REFRESH_TOKEN_ENDPOINT = "/api/auth/refreshToken"
# GDD (Diagnostic Order) endpoints # GDD (Diagnostic Order) endpoints
API_DO_WORKLIST_ENDPOINT = "/api/requests/worklist-filter" API_DO_WORKLIST_ENDPOINT = "/api/requests/worklist-filter?role=admin"
API_DO_REQUEST_DETAIL_ENDPOINT = "/api/requests" # + /{id}/validation API_DO_REQUEST_DETAIL_ENDPOINT = "/api/requests" # + /{id}/validation
API_DO_PROFESSIONALS_ENDPOINT = "/api/entity-manager/meta/modele_fr/data/nodes/pro/nodes" API_DO_PROFESSIONALS_ENDPOINT = "/api/entity-manager/meta/modele_fr/data/nodes/pro/nodes"

View File

@@ -1172,6 +1172,60 @@ def _get_column_mapping(mapping_config, mapping_column_name, source_type):
return column_mapping if column_mapping else None return column_mapping if column_mapping else None
def _strftime_to_excel_format(strftime_fmt):
"""Convert a Python strftime format string to an Excel number format string."""
mapping = [
("%Y", "YYYY"), ("%y", "YY"),
("%m", "MM"), ("%d", "DD"),
("%H", "HH"), ("%M", "MM"),
("%S", "SS"),
]
result = strftime_fmt
for strftime_token, excel_token in mapping:
result = result.replace(strftime_token, excel_token)
return result
def _get_date_format_mapping(mapping_config, mapping_column_name, source_type):
"""
Build a date format mapping for columns whose field has a strftime-style field_template.
Args:
mapping_config: List of mapping config rows
mapping_column_name: Name of the mapping column (e.g., "MainReport_PatientsList")
source_type: "Requests" or "Organizations"
Returns:
Dict: {excel_col_index: {"strftime": "%d/%m/%Y", "excel": "DD/MM/YYYY"}}
Only includes columns with a date field_template (contains '%').
"""
if not mapping_config:
return {}
result = {}
for row in mapping_config:
field_template = row.get("field_template")
if not field_template or "%" not in str(field_template):
continue
mapping_value = row.get(mapping_column_name)
if mapping_value is None or mapping_value == "":
continue
try:
excel_col_index = int(mapping_value) - 1
except (ValueError, TypeError):
continue
if excel_col_index >= 0:
result[excel_col_index] = {
"strftime": str(field_template),
"excel": _strftime_to_excel_format(str(field_template)),
}
return result
def _parse_range_dimensions(start_row, start_col, end_row, end_col, header_row_count=0): def _parse_range_dimensions(start_row, start_col, end_row, end_col, header_row_count=0):
""" """
Shared utility: Calculate dimensions from cell coordinates. Shared utility: Calculate dimensions from cell coordinates.
@@ -1485,9 +1539,11 @@ def _prepare_table_data(source_type, source, sheet_config, requests_data, organi
column_mapping = _get_column_mapping(mapping_config, source, source_type) column_mapping = _get_column_mapping(mapping_config, source, source_type)
if not column_mapping: if not column_mapping:
logging.warning(f"Column mapping '{source}' not found or empty for {target_name}") logging.warning(f"Column mapping '{source}' not found or empty for {target_name}")
return None, None return None, None, {}
return sorted_data, column_mapping date_format_mapping = _get_date_format_mapping(mapping_config, source, source_type)
return sorted_data, column_mapping, date_format_mapping
def _resize_table_range(workbook_xw, sheet_xw, target_name, start_cell, max_col, start_row, num_data_rows, header_row_count=0, target_type=TARGET_TYPE_TABLE): def _resize_table_range(workbook_xw, sheet_xw, target_name, start_cell, max_col, start_row, num_data_rows, header_row_count=0, target_type=TARGET_TYPE_TABLE):
@@ -1627,7 +1683,7 @@ def _duplicate_template_row(sheet_xw, start_cell, max_col, start_row, num_data_r
def _fill_table_with_data(sheet_xw, start_cell, start_row, start_col, sorted_data, column_mapping, def _fill_table_with_data(sheet_xw, start_cell, start_row, start_col, sorted_data, column_mapping,
value_replacement, target_name, sheet_name): value_replacement, target_name, sheet_name, date_format_mapping=None):
""" """
Fill table with data: group contiguous columns and transfer via bulk 2D arrays. Fill table with data: group contiguous columns and transfer via bulk 2D arrays.
@@ -1641,6 +1697,8 @@ def _fill_table_with_data(sheet_xw, start_cell, start_row, start_col, sorted_dat
value_replacement: Value replacement configuration (or None) value_replacement: Value replacement configuration (or None)
target_name: Target range name (for logging) target_name: Target range name (for logging)
sheet_name: Sheet name (for logging) sheet_name: Sheet name (for logging)
date_format_mapping: Optional dict {col_idx: {"strftime": ..., "excel": ...}}
Columns listed here will be written as native datetime objects.
Returns: Returns:
None (logging handles errors and success) None (logging handles errors and success)
@@ -1676,6 +1734,15 @@ def _fill_table_with_data(sheet_xw, start_cell, start_row, start_col, sorted_dat
if value_replacement: if value_replacement:
value = _apply_value_replacement(value, value_replacement) value = _apply_value_replacement(value, value_replacement)
# Convert date strings to native datetime objects
if (date_format_mapping and excel_col_index in date_format_mapping
and isinstance(value, str)):
strftime_fmt = date_format_mapping[excel_col_index]["strftime"]
try:
value = datetime.strptime(value, strftime_fmt)
except (ValueError, TypeError):
pass # keep as string if parsing fails
row_values.append(value) row_values.append(value)
data_2d.append(row_values) data_2d.append(row_values)
@@ -1687,6 +1754,18 @@ def _fill_table_with_data(sheet_xw, start_cell, start_row, start_col, sorted_dat
# Write 2D array at once (xlwings automatically maps rows × columns) # Write 2D array at once (xlwings automatically maps rows × columns)
sheet_xw.range(target_range_start).value = data_2d sheet_xw.range(target_range_start).value = data_2d
# Apply Excel number format to date columns in this group
if date_format_mapping and len(sorted_data) > 0:
last_data_row = start_row + len(sorted_data) - 1
for col_idx in col_group:
if col_idx in date_format_mapping:
col_abs = start_col + col_idx
col_letter = get_column_letter(col_abs)
excel_fmt = date_format_mapping[col_idx]["excel"]
sheet_xw.range(
f"{col_letter}{start_row}:{col_letter}{last_data_row}"
).number_format = excel_fmt
# Logging # Logging
num_data_rows = len(sorted_data) num_data_rows = len(sorted_data)
logging.info(f"Filled table {target_name} with {num_data_rows} rows " logging.info(f"Filled table {target_name} with {num_data_rows} rows "
@@ -1732,7 +1811,7 @@ def _process_sheet_xlwings(workbook_xw, sheet_config, requests_data, organizatio
return False return False
# Prepare data: filter, sort, get column mapping # Prepare data: filter, sort, get column mapping
sorted_data, column_mapping = _prepare_table_data( sorted_data, column_mapping, date_format_mapping = _prepare_table_data(
source_type, source, sheet_config, requests_data, organizations_data, source_type, source, sheet_config, requests_data, organizations_data,
requests_mapping_config, organizations_mapping_config, target_name requests_mapping_config, organizations_mapping_config, target_name
) )
@@ -1763,7 +1842,8 @@ def _process_sheet_xlwings(workbook_xw, sheet_config, requests_data, organizatio
# STEP 2-3: Fill with data (grouped contiguous columns) # STEP 2-3: Fill with data (grouped contiguous columns)
_fill_table_with_data(sheet_xw, start_cell, start_row, start_col, sorted_data, _fill_table_with_data(sheet_xw, start_cell, start_row, start_col, sorted_data,
column_mapping, value_replacement, target_name, sheet_name) column_mapping, value_replacement, target_name, sheet_name,
date_format_mapping)
else: else:
# No data - template row stays empty # No data - template row stays empty
logging.info(f"No data for target '{target_name}' ({target_type}), leaving template row empty") logging.info(f"No data for target '{target_name}' ({target_type}), leaving template row empty")