Last version of 28/03/2026
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1525,9 +1525,9 @@ def main():
|
||||
console.print("[green]✓ Data saved to JSON files[/green]")
|
||||
print()
|
||||
|
||||
# === EXCEL EXPORT === (temporarily disabled for JSON generation testing)
|
||||
# run_normal_mode_export(excel_export_enabled, excel_export_config,
|
||||
# requests_mapping_config, organizations_mapping_config)
|
||||
# === EXCEL EXPORT ===
|
||||
run_normal_mode_export(excel_export_enabled, excel_export_config,
|
||||
requests_mapping_config, organizations_mapping_config)
|
||||
|
||||
except IOError as io_err:
|
||||
logging.critical(f"Error while writing JSON file : {io_err}")
|
||||
|
||||
@@ -75,7 +75,7 @@ API_AUTH_CONFIG_TOKEN_ENDPOINT = "/api/auth/config-token"
|
||||
API_AUTH_REFRESH_TOKEN_ENDPOINT = "/api/auth/refreshToken"
|
||||
|
||||
# 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_PROFESSIONALS_ENDPOINT = "/api/entity-manager/meta/modele_fr/data/nodes/pro/nodes"
|
||||
|
||||
|
||||
@@ -1172,6 +1172,60 @@ def _get_column_mapping(mapping_config, mapping_column_name, source_type):
|
||||
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):
|
||||
"""
|
||||
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)
|
||||
if not column_mapping:
|
||||
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):
|
||||
@@ -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,
|
||||
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.
|
||||
|
||||
@@ -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)
|
||||
target_name: Target range 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:
|
||||
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:
|
||||
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)
|
||||
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)
|
||||
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
|
||||
num_data_rows = len(sorted_data)
|
||||
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
|
||||
|
||||
# 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,
|
||||
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)
|
||||
_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:
|
||||
# No data - template row stays empty
|
||||
logging.info(f"No data for target '{target_name}' ({target_type}), leaving template row empty")
|
||||
|
||||
Reference in New Issue
Block a user