Files
EDI_DELFOR_Parser/edi_parser_cummins.py
T
Dvorinka 5fbf1346d5 sefs
2025-08-05 14:09:37 +02:00

791 lines
36 KiB
Python

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import re
from datetime import datetime, date
import os
import openpyxl
from openpyxl.styles import Font, Alignment
from openpyxl.utils import get_column_letter
class EDIDelforCumminsParser:
def __init__(self, filepath=None):
self.root = tk.Tk()
self.root.title("EDI Cummins Parser")
self.root.geometry("1200x800")
self.header_info = {}
self.partner_info = {}
self.delivery_schedules = []
self.line_items = []
# Handle window close event
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
self.setup_ui()
if filepath:
self.load_file(filepath)
def setup_ui(self):
main_frame = ttk.Frame(self.root)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
btn_frame = ttk.Frame(main_frame)
btn_frame.pack(fill=tk.X, pady=(0, 10))
# Style configuration for buttons
style = ttk.Style()
style.configure('Excel.TButton',
background='#217346', # Excel green color
foreground='white',
font=('Segoe UI', 10, 'bold'),
padding=5)
# Add buttons with padding and styling
btn_back = ttk.Button(btn_frame, text="Zpět na hlavní okno", command=self.back_to_main)
btn_export = ttk.Button(btn_frame,
text="📊 Export do Excelu",
command=self.export_to_excel,
style='Excel.TButton')
# Pack buttons with padding
btn_back.pack(side=tk.LEFT, padx=(0, 5))
btn_export.pack(side=tk.LEFT)
self.notebook = ttk.Notebook(main_frame)
self.notebook.pack(fill=tk.BOTH, expand=True)
self.info_frame = ttk.Frame(self.notebook)
self.notebook.add(self.info_frame, text="Základní informace")
self.delivery_frame = ttk.Frame(self.notebook)
self.notebook.add(self.delivery_frame, text="Plán dodávek")
self.stats_frame = ttk.Frame(self.notebook)
self.notebook.add(self.stats_frame, text="Statistiky")
self.setup_info_tab()
self.setup_delivery_tab()
self.setup_stats_tab()
def setup_info_tab(self):
text_frame = ttk.Frame(self.info_frame)
text_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.info_text = tk.Text(text_frame, wrap=tk.WORD, font=('Courier', 10))
scrollbar = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=self.info_text.yview)
self.info_text.configure(yscrollcommand=scrollbar.set)
self.info_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
def setup_delivery_tab(self):
tree_frame = ttk.Frame(self.delivery_frame)
tree_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Removed 'Jednotka' column as requested
columns = ('Položka', 'Popis', 'Datum', 'Množství', 'Typ', 'SCC', 'Release')
self.delivery_tree = ttk.Treeview(tree_frame, columns=columns, show='headings', height=15)
for col in columns:
self.delivery_tree.heading(col, text=col)
if col == 'Popis':
self.delivery_tree.column(col, width=200)
elif col == 'Položka':
self.delivery_tree.column(col, width=100)
else:
self.delivery_tree.column(col, width=80)
v_scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=self.delivery_tree.yview)
h_scrollbar = ttk.Scrollbar(tree_frame, orient=tk.HORIZONTAL, command=self.delivery_tree.xview)
self.delivery_tree.configure(yscrollcommand=v_scrollbar.set, xscrollcommand=h_scrollbar.set)
self.delivery_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
v_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
h_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
def setup_stats_tab(self):
stats_frame = ttk.Frame(self.stats_frame)
stats_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.stats_text = tk.Text(stats_frame, wrap=tk.WORD, font=('Courier', 10))
stats_scrollbar = ttk.Scrollbar(stats_frame, orient=tk.VERTICAL, command=self.stats_text.yview)
self.stats_text.configure(yscrollcommand=stats_scrollbar.set)
self.stats_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
stats_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
def parse_date(self, date_str, format_code):
try:
if format_code == '102':
return datetime.strptime(date_str, '%Y%m%d').strftime('%d.%m.%Y')
else:
return date_str
except:
return date_str
def parse_edi_datetime(self, datetime_str):
try:
if ':' in datetime_str:
date_part, time_part = datetime_str.split(':')
full_date = '20' + date_part
formatted_date = datetime.strptime(full_date, '%Y%m%d').strftime('%d.%m.%Y')
formatted_time = datetime.strptime(time_part, '%H%M').strftime('%H:%M')
return f"{formatted_date} {formatted_time}"
return datetime_str
except:
return datetime_str
def get_scc_description(self, scc_code):
scc_map = {
'10': 'Backlog',
'1': 'Firm',
'4': 'Forecast'
}
return scc_map.get(scc_code, f'{scc_code}')
def parse_edi_file(self, content):
lines = content.strip().split("'")
self.header_info = {}
self.partner_info = {}
self.delivery_schedules = []
self.line_items = []
# Current parsing state
current_part_number = ''
current_description = ''
current_location = ''
current_po = ''
current_scc = ''
current_release = ''
# Track current line item details
current_line_item = None
# Temporary storage for quantity waiting for date
pending_quantities = []
def create_or_update_line_item():
nonlocal current_line_item
if not current_part_number:
return None
line_item = next((item for item in self.line_items
if item['Položka'] == current_part_number), None)
if not line_item:
line_item = {
'Položka': current_part_number,
'Popis': current_description,
'Objednávka': current_po,
'Lokace': current_location,
'RFF': {}
}
self.line_items.append(line_item)
# Update current line item reference
current_line_item = line_item
return line_item
for line in lines:
line = line.strip()
if not line:
continue
if line.startswith('UNB'):
parts = line.split('+')
if len(parts) >= 5:
self.header_info['Odesílatel'] = parts[2]
self.header_info['Příjemce_kód'] = parts[3]
self.header_info['Datum/Čas'] = self.parse_edi_datetime(parts[4])
elif line.startswith('UNH'):
parts = line.split('+')
if len(parts) >= 2:
self.header_info['ID zprávy'] = parts[1]
elif line.startswith('BGM'):
parts = line.split('+')
if len(parts) >= 3:
self.header_info['Číslo zprávy'] = parts[2]
elif line.startswith('DTM'):
parts = line.split('+')
if len(parts) >= 2:
dtm_parts = parts[1].split(':')
if len(dtm_parts) >= 3:
code = dtm_parts[0]
value = dtm_parts[1]
fmt = dtm_parts[2]
formatted_date = self.parse_date(value, fmt)
if code == '137':
self.header_info['Datum dokumentu'] = formatted_date
elif code == '2':
# This is a delivery date - match with pending quantities
# Only create entries if we have quantities to process
if pending_quantities:
# For SCC 10 (Backlog), we only take the first quantity
if current_scc == '10' and len(pending_quantities) > 0:
qty_info = pending_quantities[0]
# Create line item if it doesn't exist
line_item = next((item for item in self.line_items if item['Položka'] == current_part_number), None)
if not line_item:
line_item = {
'Položka': current_part_number,
'Popis': current_description,
'Objednávka': current_po,
'Lokace': current_location
}
self.line_items.append(line_item)
delivery = {
'Položka': current_part_number,
'Popis': current_description,
'Datum': formatted_date,
'Množství': qty_info['quantity'],
'Typ': qty_info['type'],
'SCC': self.get_scc_description(current_scc),
'Release': current_release,
'Objednávka': current_po
}
self.delivery_schedules.append(delivery)
else:
# For other SCCs, process all quantities
for qty_info in pending_quantities:
delivery = {
'Položka': current_part_number,
'Popis': current_description,
'Datum': formatted_date,
'Množství': qty_info['quantity'],
'Typ': qty_info['type'],
'SCC': self.get_scc_description(current_scc),
'Release': current_release
}
self.delivery_schedules.append(delivery)
pending_quantities.clear()
# Don't reset release here to maintain it for next entries
elif line.startswith('NAD'):
parts = line.split('+')
if len(parts) >= 3:
role = parts[1]
if role == 'SU': # Supplier
name_parts = [p.replace('?+', '').replace('?', '').strip() for p in parts[4:] if p]
self.partner_info['Dodavatel'] = ' '.join(name_parts)
elif role == 'ST': # Ship To
name_parts = [p.replace('?+', '').replace('?', '').strip() for p in parts[4:] if p]
self.partner_info['Příjemce'] = ' '.join(name_parts)
# Store the full address for delivery location
if len(parts) > 5: # If there are address components
address_parts = []
# Get address lines (parts[5] and beyond)
for part in parts[5:]:
if ':' in part: # Skip parts with qualifiers
break
address_parts.append(part.replace('?+', '').replace('?', '').strip())
if address_parts:
self.partner_info['Dodací adresa'] = ', '.join(address_parts)
# If no specific address found, use the recipient name as fallback
if not self.partner_info['Dodací adresa'] and name_parts:
self.partner_info['Dodací adresa'] = ' '.join(name_parts)
elif line.startswith('LIN'):
# Save previous line item if it exists
if current_part_number:
# Process previous line item if exists
create_or_update_line_item()
parts = line.split('+')
# Process LIN segment
if len(parts) >= 4:
# Reset part information for new line item
current_part_number = ''
current_description = ''
current_scc = ''
current_release = ''
current_line_item = None
pending_quantities = []
# Try to find part number in the LIN segment
for i, part in enumerate(parts[3:], 3): # Skip the first 3 parts (LIN, line number, action code)
# Process part
if ':' in part: # If the part contains a colon, it might be a part number
part_info = part.split(':')
# Process part info
if len(part_info) >= 2 and part_info[1] == 'IN': # Look for part number with 'IN' qualifier
current_part_number = part_info[0]
# Found part number with IN qualifier
break
elif not current_part_number: # If no 'IN' qualifier found, take the first part
current_part_number = part_info[0]
# Using first part as part number
# If still no part number found, try to get it from the last part
if not current_part_number and parts[3:]:
current_part_number = parts[3].split(':')[0]
# Using fallback part number
# Final part number processed
elif line.startswith('IMD'):
parts = line.split('+')
if len(parts) >= 4:
# Extract item description - fixed to properly handle the format
# Looking for the 4th element which contains the description
desc_part = parts[3] if len(parts) > 3 else ''
# Remove leading colons and extract the actual description
if desc_part.startswith(':::'):
current_description = desc_part[3:].strip()
elif desc_part.startswith('::'):
current_description = desc_part[2:].strip()
elif desc_part.startswith(':'):
current_description = desc_part[1:].strip()
else:
current_description = desc_part.strip()
# Clean up any remaining formatting
current_description = current_description.replace(':', '').strip()
elif line.startswith('LOC'):
parts = line.split('+')
if len(parts) >= 3:
current_location = parts[2]
elif line.startswith('RFF'):
parts = line.split('+')
# Process RFF segment
if len(parts) >= 2:
ref_parts = parts[1].split(':')
if len(ref_parts) >= 2:
ref_type = ref_parts[0]
ref_value = ref_parts[1]
# Found RFF reference
# Create or update line item if it doesn't exist
if not current_line_item:
# Create new line item if none exists
create_or_update_line_item()
# Store the reference in the current line item
if current_line_item:
if 'RFF' not in current_line_item:
current_line_item['RFF'] = {}
current_line_item['RFF'][ref_type] = ref_value
# RFF stored in line item
# Special handling for order numbers
if ref_type == 'ON':
current_po = ref_value
current_line_item['Objednávka'] = current_po
# Order number set
elif ref_type == 'RE':
current_release = ref_value
# Clear any pending quantities to ensure release number is applied to new quantities
pending_quantities = []
# Release number set
else:
# No line item available for RFF
pass
elif line.startswith('SCC'):
parts = line.split('+')
if len(parts) >= 2:
current_scc = parts[1]
# Clear pending quantities when new SCC starts to prevent duplicates
pending_quantities = []
# Only reset release for backlog (SCC 10)
if current_scc == '10':
current_release = ''
elif line.startswith('QTY'):
parts = line.split('+')
if len(parts) >= 2:
qty_parts = parts[1].split(':')
if len(qty_parts) >= 2:
qty_type = qty_parts[0]
quantity = qty_parts[1]
# Removed unit extraction as we don't need it
# Determine quantity type
qty_type_desc = 'Neznámý'
if qty_type == '1':
qty_type_desc = 'Dodávka'
elif qty_type == '3':
qty_type_desc = 'Kumulativní'
elif qty_type == '48':
qty_type_desc = 'Plánované'
# Store quantity info waiting for corresponding date
pending_quantities.append({
'quantity': quantity,
'type': qty_type_desc
})
# Store line items for reference
unique_parts = {}
for delivery in self.delivery_schedules:
part_num = delivery['Položka']
if part_num not in unique_parts:
unique_parts[part_num] = {
'Položka': part_num,
'Popis': delivery['Popis']
}
self.line_items = list(unique_parts.values())
def load_file(self, filepath=None):
if filepath:
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
self.parse_edi_file(content)
self.display_data()
return True
except Exception as e:
messagebox.showerror("Chyba", f"Nelze načíst soubor: {str(e)}")
return False
return False
def display_data(self):
# Display header info
self.info_text.delete(1.0, tk.END)
info_content = "=== HLAVIČKA DOKUMENTU ===\n"
for key, value in self.header_info.items():
if key != 'Příjemce_kód':
info_content += f"{key}: {value}\n"
info_content += "\n=== INFORMACE O PARTNERECH ===\n"
for key, value in self.partner_info.items():
info_content += f"{key}: {value}\n"
self.info_text.insert(1.0, info_content)
# Display delivery schedules
for item in self.delivery_tree.get_children():
self.delivery_tree.delete(item)
# Sort deliveries by date
def date_sort_key(delivery):
date_str = delivery.get('Datum', '')
try:
return datetime.strptime(date_str, '%d.%m.%Y') if date_str else datetime.max
except:
return datetime.max
sorted_deliveries = sorted(self.delivery_schedules, key=date_sort_key)
for delivery in sorted_deliveries:
self.delivery_tree.insert('', tk.END, values=(
delivery.get('Položka', ''),
delivery.get('Popis', ''),
delivery.get('Datum', ''),
delivery.get('Množství', ''),
delivery.get('Typ', ''),
delivery.get('SCC', ''),
delivery.get('Release', '')
))
# Display statistics
self.stats_text.delete(1.0, tk.END)
stats_content = "=== STATISTIKY ===\n"
stats_content += f"Celkový počet dodávek: {len(self.delivery_schedules)}\n"
stats_content += f"Počet různých položek: {len(self.line_items)}\n"
# Group by SCC
scc_stats = {}
total_qty = 0
for delivery in self.delivery_schedules:
scc = delivery.get('SCC', 'Neznámý')
qty_str = delivery.get('Množství', '0')
try:
qty = int(qty_str)
total_qty += qty
if scc not in scc_stats:
scc_stats[scc] = {'count': 0, 'total_qty': 0}
scc_stats[scc]['count'] += 1
scc_stats[scc]['total_qty'] += qty
except:
pass
stats_content += f"Celkové množství: {total_qty:,} kusů\n\n"
stats_content += "=== STATISTIKY PO SCC ===\n"
for scc, stats in scc_stats.items():
stats_content += f"{scc}: {stats['count']} dodávek, {stats['total_qty']:,} kusů\n"
self.stats_text.insert(1.0, stats_content)
def on_closing(self):
"""Handle window close event"""
self.root.destroy() # Close the current window
def back_to_main(self):
"""Closes the current window"""
self.root.destroy()
def get_week_number(self, date_str):
"""Convert date string to ISO week number"""
try:
# Handle different date formats
if '.' in date_str:
date_obj = datetime.strptime(date_str, '%d.%m.%Y').date()
else:
date_obj = datetime.strptime(date_str, '%Y%m%d').date()
return date_obj.isocalendar()[1] # Returns ISO week number
except Exception as e:
# Log error silently
return ""
def export_to_excel(self):
"""Export delivery data to Excel with calendar weeks, color-coded by part"""
if not self.delivery_schedules:
messagebox.showwarning("Upozornění", "Žádná data k exportu")
return
try:
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Dodávky"
# Get unique part numbers and assign colors
unique_parts = list(set([item.get('Položka', '') for item in self.delivery_schedules if item.get('Položka')]))
# Generate distinct colors for each part
colors = [
'FFE6B8', 'B8D1E6', 'E6B8B8', 'B8E6C3', 'E6D5B8',
'D1B8E6', 'B8E6E6', 'E6B8D1', 'B8C3E6', 'E6E6B8',
'B8E6D1', 'E6B8E6', 'B8E6B8', 'E6C3B8', 'B8D1E6',
'E6B8C3', 'B8E6D9', 'E6B8D9', 'B8E6B8', 'E6B8FF'
]
part_colors = {}
for i, part in enumerate(unique_parts):
part_colors[part] = colors[i % len(colors)]
# Headers in requested order: položka, datum, týden, množství, SCC, zbytek ad lib
headers = ["Položka", "Datum", "Týden", "Množství", "SCC", "Dodací místo"]
for col_num, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col_num, value=header)
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal='center')
# Add legend headers
legend_headers = ["Legenda:", "Položka", "Popis"]
for col_num, header in enumerate(legend_headers, 10): # Start from column J
cell = ws.cell(row=1, column=col_num, value=header)
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal='center')
# Prepare data for sorting by item and date
prepared_data = []
for item in self.delivery_schedules:
# Get item number (Položka)
part_number = item.get('Položka', '')
# Parse date for sorting
date_str = item.get('Datum', '')
date_for_sort = None
if date_str:
try:
if '.' in date_str:
date_parts = date_str.split('.')
if len(date_parts) == 3:
date_for_sort = datetime(int(date_parts[2]), int(date_parts[1]), int(date_parts[0]))
else:
# Handle YYYYMMDD format if needed
date_for_sort = datetime.strptime(date_str, '%Y%m%d')
except (ValueError, IndexError):
pass
prepared_data.append({
'part_number': part_number,
'date_for_sort': date_for_sort or datetime.max,
'item': item
})
# Sort by item and date
prepared_data.sort(key=lambda x: (str(x['part_number'] or ''), x['date_for_sort']))
# Add data to worksheet
row_num = 2
for data in prepared_data:
item = data['item']
# Get week number from date
week_num = self.get_week_number(item.get('Datum', ''))
# Format quantity as number, removing any leading quotes
quantity = item.get('Množství', '')
if isinstance(quantity, str):
quantity = quantity.strip("'")
try:
quantity = float(quantity) if quantity else 0
except (ValueError, TypeError):
quantity = 0
# Format week number as number
try:
week_num = int(week_num) if week_num else 0
except (ValueError, TypeError):
week_num = 0
# Get part number
part_number = item.get('Položka', '')
# Get SCC description
scc = item.get('SCC', '')
scc_desc = self.get_scc_description(str(scc)) if scc else ''
# Get delivery location
delivery_location = str(self.partner_info.get('Dodací adresa', '') or '')
if not delivery_location.strip():
delivery_location = 'Cummins Inc., 500 Jackson Street, Columbus, IN 47201, USA' # Default Cummins address
# Get part description for legend
part_description = item.get('Popis', '')
# Get color for this part
part_color = part_colors.get(part_number, 'FFFFFF') # Default to white if part not found
# 1. Položka (as text with colored background and part number as text)
cell = ws.cell(row=row_num, column=1, value=str(part_number))
cell.number_format = '@'
cell.fill = openpyxl.styles.PatternFill(start_color=part_color, end_color=part_color, fill_type='solid')
cell.font = Font(color='000000') # Ensure text is black for visibility
# 2. Datum (formatted date) - not colored
date_str = item.get('Datum', '')
try:
if date_str:
if '.' in date_str:
date_obj = datetime.strptime(date_str, '%d.%m.%Y')
else:
date_obj = datetime.strptime(date_str, '%Y%m%d')
cell = ws.cell(row=row_num, column=2, value=date_obj)
cell.number_format = 'DD.MM.YYYY'
else:
cell = ws.cell(row=row_num, column=2, value='')
except:
cell = ws.cell(row=row_num, column=2, value=date_str)
# 3. Týden (week number) - not colored
cell = ws.cell(row=row_num, column=3, value=week_num)
cell.number_format = '0'
# 4. Množství (quantity as number) - not colored
try:
if isinstance(quantity, (int, float)):
qty_value = float(quantity)
else:
qty_str = str(quantity).strip().replace("'", "")
qty_value = float(qty_str) if qty_str.replace('.', '', 1).isdigit() else 0.0
cell = ws.cell(row=row_num, column=4, value=qty_value)
cell.number_format = '0'
except (ValueError, AttributeError):
cell = ws.cell(row=row_num, column=4, value=0.0)
cell.number_format = '0'
# 5. SCC (as text) - not colored
cell = ws.cell(row=row_num, column=5, value=str(scc_desc))
cell.number_format = '@'
# 6. Dodací místo (delivery address as text) - not colored
cell = ws.cell(row=row_num, column=6, value=delivery_location)
cell.number_format = '@'
row_num += 1
# Apply number formatting to numeric columns
for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
# Skip empty rows or rows with insufficient columns
if len(row) < 6: # We need at least 6 columns (0-5)
continue
# Format week number (column 1) as number with no decimal places
if row[0].value is not None and row[0].value != '': # Column 1 (0-based index 0)
if isinstance(row[0].value, (int, float)):
row[0].number_format = '0'
# Format part number (column 3) as number with no decimal places if it's a number
if len(row) > 2 and row[2].value is not None and row[2].value != '': # Column 3 (0-based index 2)
if isinstance(row[2].value, (int, float)):
row[2].number_format = '0'
# Format quantity (column 4) as number with no decimal places
if len(row) > 4 and row[4].value is not None and row[4].value != '': # Column 5 (0-based index 4)
if isinstance(row[4].value, (int, float)):
row[4].number_format = '0'
# Add legend headers (only in columns J and K)
ws.cell(row=1, column=10, value="Legenda:").font = Font(bold=True)
ws.cell(row=1, column=11, value="Popis").font = Font(bold=True)
# Clear any existing header in column L
if ws.cell(row=1, column=12).value == "Popis":
ws.cell(row=1, column=12, value="")
# Add legend items starting from row 2
legend_row = 2
for part_number, color in part_colors.items():
# Get part description
part_description = ''
for item in self.delivery_schedules:
if item.get('Položka') == part_number:
part_description = item.get('Popis', '')
break
# Set column J width to 0.75 inches (approximately 8.43 units in Excel)
ws.column_dimensions['J'].width = 10
# Create a cell with colored background and part number as text
legend_cell = ws.cell(row=legend_row, column=10, value=str(part_number))
legend_cell.fill = openpyxl.styles.PatternFill(
start_color=color, end_color=color, fill_type='solid')
legend_cell.font = Font(color='000000', bold=True) # Black text, bold
legend_cell.alignment = Alignment(horizontal='center')
# Part description in next column
ws.cell(row=legend_row, column=11, value=part_description)
legend_row += 1
# Auto-adjust column widths for all columns
for col in ws.columns:
max_length = 0
column_letter = get_column_letter(col[0].column)
# Skip the color swatch column (J) for width adjustment
if column_letter == 'J':
ws.column_dimensions[column_letter].width = 10 # Fixed width for color swatch (0.75")
continue
for cell in col:
try:
# For dates, use the formatted string length
if hasattr(cell, 'is_date') and cell.is_date:
cell_value = cell.value.strftime('%d.%m.%Y') if cell.value else ''
else:
cell_value = str(cell.value) if cell.value is not None else ''
if len(cell_value) > max_length:
max_length = len(cell_value)
except:
pass
# Set a reasonable maximum width to prevent extremely wide columns
adjusted_width = min((max_length + 2), 30)
# Set minimum width for better readability
if column_letter in ['A', 'B', 'C', 'D', 'E', 'F', 'G']: # Main data columns
adjusted_width = max(adjusted_width, 12)
elif column_letter in ['K', 'L']: # Legend columns
adjusted_width = max(adjusted_width, 20)
ws.column_dimensions[column_letter].width = adjusted_width
# Add a summary sheet with just week and quantity
ws_summary = wb.create_sheet("Přehled")
# Save the file
filename = f"dodavky_cummins_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
filepath = filedialog.asksaveasfilename(
defaultextension=".xlsx",
filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")],
initialfile=filename
)
if filepath:
wb.save(filepath)
messagebox.showinfo("Hotovo", f"Data byla úspěšně exportována do souboru:\n{filepath}")
except Exception as e:
messagebox.showerror("Chyba", f"Při exportu došlo k chybě: {str(e)}")
def run(self):
self.root.mainloop()
if __name__ == "__main__":
# When run directly, use the main parser to handle file selection
from edi_parser_main import EDIUnifiedParser
EDIUnifiedParser()