Add xlsxwriter-based Excel generation scripts with openpyxl implementation

- Created create_excel_xlsxwriter.py and update_excel_xlsxwriter.py
- Uses openpyxl exclusively to preserve Excel formatting and formulas
- Updated server.js to use new xlsxwriter scripts for form submissions
- Maintains all original functionality while ensuring proper Excel file handling

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
andrei
2025-09-22 13:53:06 +00:00
commit 0e2e1bddba
842 changed files with 316330 additions and 0 deletions

149
create_excel.py Normal file
View File

@@ -0,0 +1,149 @@
#!/usr/bin/env python3
import json
import os
import shutil
import datetime
import re
from pathlib import Path
from dateutil.relativedelta import relativedelta
from update_excel import update_excel_variables
def create_excel_from_template():
"""
Create a copy of the Excel template and save it to the output folder,
then inject variables from config.json into the Variables sheet.
"""
# Define paths
script_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(script_dir, 'config.json')
# Look for any Excel template in the template directory
template_dir = os.path.join(script_dir, 'template')
template_files = [f for f in os.listdir(template_dir) if f.endswith('.xlsx')]
if not template_files:
print("Error: No Excel template found in the template directory")
return False
template_path = os.path.join(template_dir, template_files[0])
output_dir = os.path.join(script_dir, 'output')
# Ensure output directory exists
os.makedirs(output_dir, exist_ok=True)
# Read config.json to get store_name, starting_date, and duration
try:
with open(config_path, 'r') as f:
config = json.load(f)
user_data = config.get('user_data', {})
store_name = user_data.get('store_name', '')
starting_date = user_data.get('starting_date', '')
duration = user_data.get('duration', 36)
# If store_name is empty, use a default value
if not store_name:
store_name = "Your Store"
# Calculate years array based on starting_date and duration
years = calculate_years(starting_date, duration)
print(f"Years in the period: {years}")
except Exception as e:
print(f"Error reading config file: {e}")
return False
# Use first and last years from the array in the filename
year_range = ""
if years and len(years) > 0:
if len(years) == 1:
year_range = f"{years[0]}"
else:
year_range = f"{years[0]}-{years[-1]}"
else:
# Fallback to current year if years array is empty
current_year = datetime.datetime.now().year
year_range = f"{current_year}"
# Create output filename with store_name and year range
output_filename = f"Footprints AI for {store_name} - Retail Media Business Case Calculations {year_range}.xlsx"
output_path = os.path.join(output_dir, output_filename)
# Copy the template to the output directory with the new name
try:
shutil.copy2(template_path, output_path)
print(f"Excel file created successfully: {output_path}")
# Update the Excel file with variables from config.json
print("Updating Excel file with variables from config.json...")
update_result = update_excel_variables(output_path)
if update_result:
print("Excel file updated successfully with variables from config.json")
else:
print("Warning: Failed to update Excel file with variables from config.json")
return True
except Exception as e:
print(f"Error creating Excel file: {e}")
return False
def calculate_years(starting_date, duration):
"""
Calculate an array of years that appear in the period from starting_date for duration months.
Args:
starting_date (str): Date in format dd/mm/yyyy or dd.mm.yyyy
duration (int): Number of months, including the starting month
Returns:
list: Array of years in the period [year1, year2, ...]
"""
# Default result if we can't parse the date
default_years = [datetime.datetime.now().year]
# If starting_date is empty, return current year
if not starting_date:
return default_years
try:
# Try to parse the date, supporting both dd/mm/yyyy and dd.mm.yyyy formats
if '/' in starting_date:
day, month, year = map(int, starting_date.split('/'))
elif '.' in starting_date:
day, month, year = map(int, starting_date.split('.'))
elif '-' in starting_date:
# Handle ISO format (yyyy-mm-dd)
date_parts = starting_date.split('-')
if len(date_parts) == 3:
year, month, day = map(int, date_parts)
else:
# Default to current date if format is not recognized
return default_years
else:
# If format is not recognized, return default
return default_years
# Create datetime object for starting date
start_date = datetime.datetime(year, month, day)
# Calculate end date (starting date + duration months - 1 day)
end_date = start_date + relativedelta(months=duration-1)
# Create a set of years (to avoid duplicates)
years_set = set()
# Add starting year
years_set.add(start_date.year)
# Add ending year
years_set.add(end_date.year)
# If there are years in between, add those too
for y in range(start_date.year + 1, end_date.year):
years_set.add(y)
# Convert set to sorted list
return sorted(list(years_set))
except Exception as e:
print(f"Error calculating years: {e}")
return default_years
if __name__ == "__main__":
create_excel_from_template()