diff --git a/config.json b/config.json index 761aeca..5a10535 100644 --- a/config.json +++ b/config.json @@ -5,9 +5,9 @@ "company_name": "Footprints AI", "email": "denisa@example.com", "phone": "+40 712 345 678", - "store_name": "Profi Romania", + "store_name": "Carrefour Romania", "country": "Romania", - "starting_date": "2025-02-01", + "starting_date": "01.01.2026", "duration": 36, "store_types": ["convenience", "supermarket", "hypermarket"], "open_days_per_month": 26, diff --git a/update_excel.py b/update_excel.py index ef3584f..33a13a2 100755 --- a/update_excel.py +++ b/update_excel.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import json import os +import re import openpyxl from openpyxl.utils import get_column_letter @@ -107,101 +108,100 @@ def update_excel_variables(excel_path): # Update sheet names - replace {store_name} with actual store name store_name = user_data.get('store_name', '') if store_name: + # Dictionary to store old sheet name to new sheet name mappings + sheet_name_mapping = {} + # Make a copy of the sheet names to avoid modifying during iteration sheet_names = wb.sheetnames.copy() - - # Keep track of used sheet names to avoid duplicates - used_sheet_names = set() - for sheet_name in sheet_names: if '{store_name}' in sheet_name: - # Replace the placeholder with the store name new_sheet_name = sheet_name.replace('{store_name}', store_name) - - # Excel has a 31-character limit for sheet names - if len(new_sheet_name) > 31: - # Extract parts of the sheet name (assuming format like "2025 – Forecast {store_name}") - parts = sheet_name.split('{store_name}') - prefix = parts[0] if parts else "" - suffix = parts[1] if len(parts) > 1 else "" - - # Calculate how much space we have for the store name - available_chars = 31 - len(prefix) - len(suffix) - - # If we have space for at least part of the store name - if available_chars > 0: - # Use as much of the store name as possible - truncated_store_name = store_name[:available_chars] - new_sheet_name = prefix + truncated_store_name + suffix - else: - # If no space for store name, use a more aggressive approach - year_part = sheet_name.split('–')[0].strip() if '–' in sheet_name else "" - # Create a shorter name using just the year and abbreviated store name - abbrev_store = store_name[:15] if len(store_name) > 15 else store_name - new_sheet_name = f"{year_part} {abbrev_store}"[:31] - - # Remove any invalid characters for Excel sheet names - invalid_chars = [':', '\\', '/', '?', '*', '[', ']'] - for char in invalid_chars: - new_sheet_name = new_sheet_name.replace(char, '_') - - # Ensure the name is unique - base_name = new_sheet_name - counter = 1 - while new_sheet_name in used_sheet_names: - suffix = f" ({counter})" - new_sheet_name = f"{base_name[:31-len(suffix)]}{suffix}" - counter += 1 - - used_sheet_names.add(new_sheet_name) - - try: - # Get the sheet by its old name - sheet = wb[sheet_name] - # Set the new title - sheet.title = new_sheet_name - print(f"Renamed sheet '{sheet_name}' to '{new_sheet_name}'") - except Exception as e: - print(f"Error renaming sheet '{sheet_name}': {e}") - - # Save the workbook with error handling - try: - # First try saving with normal mode - wb.save(excel_path) - print(f"Excel file updated successfully: {excel_path}") - return True - except Exception as save_error: - print(f"Warning: Error saving Excel file: {save_error}") + # Get the sheet by its old name + sheet = wb[sheet_name] + # Set the new title + sheet.title = new_sheet_name + # Store the mapping + sheet_name_mapping[sheet_name] = new_sheet_name + print(f"Renamed sheet '{sheet_name}' to '{new_sheet_name}'") - try: - # Try with a different approach - save to a new file and then replace - temp_path = excel_path + ".temp" - wb.save(temp_path) - - # Close any potential file handles - wb.close() - - # If the original file exists, try to remove it - if os.path.exists(excel_path): - try: - os.remove(excel_path) - except Exception as remove_error: - print(f"Warning: Could not remove original file: {remove_error}") - # If we can't remove it, use a new filename - excel_path = excel_path.replace(".xlsx", f"_new_{int(datetime.datetime.now().timestamp())}.xlsx") - - # Rename the temp file to the target file - os.rename(temp_path, excel_path) - print(f"Excel file saved with alternative method: {excel_path}") - return True - except Exception as alt_save_error: - print(f"Error: Failed to save Excel file with alternative method: {alt_save_error}") - return False + # Update formulas in the Graphics sheet to reference the new sheet names + if sheet_name_mapping and 'Graphics' in wb.sheetnames: + print("Updating formulas in Graphics sheet...") + update_formulas_in_graphics_sheet(wb, sheet_name_mapping) + + # Save the workbook + wb.save(excel_path) + print(f"Excel file updated successfully: {excel_path}") + return True except Exception as e: print(f"Error updating Excel file: {e}") return False +def update_formulas_in_graphics_sheet(workbook, sheet_name_mapping): + """ + Update formulas in the Graphics sheet to reference the new sheet names + + Args: + workbook: The openpyxl workbook object + sheet_name_mapping: Dictionary mapping old sheet names to new sheet names + """ + try: + graphics_sheet = workbook['Graphics'] + print("Found Graphics sheet, updating formulas...") + + # Iterate through all cells in the Graphics sheet + for row in graphics_sheet.iter_rows(): + for cell in row: + # Check if the cell contains a formula + if cell.data_type == 'f' and cell.value: + try: + # Get the formula as a string + formula = cell.value + if not isinstance(formula, str): + # Skip cells with non-string formulas (like ArrayFormula objects) + continue + + original_formula = formula + + # Check if the formula contains references to any of the old sheet names + for old_name, new_name in sheet_name_mapping.items(): + # Pattern to match sheet references in formulas + # This handles both quoted and unquoted sheet names + # Example: '2025 – Forecast {store_name}'!$B$10 or [2025 – Forecast {store_name}]!$B$10 + + # Handle quoted sheet names: 'Sheet Name'! + pattern1 = f"'({re.escape(old_name)})'" + replacement1 = f"'{new_name}'" + formula = re.sub(pattern1, replacement1, formula) + + # Handle unquoted sheet names: SheetName! + pattern2 = f"([^']|^)({re.escape(old_name)})!" + replacement2 = f"\\1{new_name}!" + formula = re.sub(pattern2, replacement2, formula) + + # Handle sheet names in square brackets: [Sheet Name] + pattern3 = f"\\[({re.escape(old_name)})\\]" + replacement3 = f"[{new_name}]" + formula = re.sub(pattern3, replacement3, formula) + + # If the formula was changed, update the cell + if formula != original_formula: + try: + cell.value = formula + print(f"Updated formula in cell {cell.coordinate}: {original_formula} -> {formula}") + except Exception as e: + print(f"Error updating formula in cell {cell.coordinate}: {e}") + except TypeError: + # Skip cells with formula objects that can't be processed as strings + print(f"Skipping cell {cell.coordinate} with non-string formula type: {type(cell.value)}") + + print("Finished updating formulas in Graphics sheet") + except KeyError: + print("Graphics sheet not found, skipping formula updates") + except Exception as e: + print(f"Error updating formulas in Graphics sheet: {e}") + if __name__ == "__main__": # For testing purposes import sys