mirror of
https://github.com/Dvorinka/EDI_DELFOR_Parser.git
synced 2026-06-04 04:22:58 +00:00
sefs
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+170
-78
@@ -125,7 +125,7 @@ class EDIDelforCumminsParser:
|
|||||||
'1': 'Firm',
|
'1': 'Firm',
|
||||||
'4': 'Forecast'
|
'4': 'Forecast'
|
||||||
}
|
}
|
||||||
return scc_map.get(scc_code, f'SCC-{scc_code}')
|
return scc_map.get(scc_code, f'{scc_code}')
|
||||||
|
|
||||||
def parse_edi_file(self, content):
|
def parse_edi_file(self, content):
|
||||||
lines = content.strip().split("'")
|
lines = content.strip().split("'")
|
||||||
@@ -521,7 +521,7 @@ class EDIDelforCumminsParser:
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
def export_to_excel(self):
|
def export_to_excel(self):
|
||||||
"""Export delivery data to Excel with calendar weeks"""
|
"""Export delivery data to Excel with calendar weeks, color-coded by part"""
|
||||||
if not self.delivery_schedules:
|
if not self.delivery_schedules:
|
||||||
messagebox.showwarning("Upozornění", "Žádná data k exportu")
|
messagebox.showwarning("Upozornění", "Žádná data k exportu")
|
||||||
return
|
return
|
||||||
@@ -531,25 +531,68 @@ class EDIDelforCumminsParser:
|
|||||||
ws = wb.active
|
ws = wb.active
|
||||||
ws.title = "Dodávky"
|
ws.title = "Dodávky"
|
||||||
|
|
||||||
# Headers with week number
|
# Get unique part numbers and assign colors
|
||||||
headers = ["Týden", "Datum", "Položka", "Popis", "Množství", "Typ", "SCC", "Release", "Dodací místo"]
|
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):
|
for col_num, header in enumerate(headers, 1):
|
||||||
cell = ws.cell(row=1, column=col_num, value=header)
|
cell = ws.cell(row=1, column=col_num, value=header)
|
||||||
cell.font = Font(bold=True)
|
cell.font = Font(bold=True)
|
||||||
cell.alignment = Alignment(horizontal='center')
|
cell.alignment = Alignment(horizontal='center')
|
||||||
|
|
||||||
# Add data - sort by date from oldest to newest
|
# Add legend headers
|
||||||
def parse_date(date_str):
|
legend_headers = ["Legenda:", "Položka", "Popis"]
|
||||||
try:
|
for col_num, header in enumerate(legend_headers, 10): # Start from column J
|
||||||
if '.' in date_str:
|
cell = ws.cell(row=1, column=col_num, value=header)
|
||||||
return datetime.strptime(date_str, '%d.%m.%Y').date()
|
cell.font = Font(bold=True)
|
||||||
else:
|
cell.alignment = Alignment(horizontal='center')
|
||||||
return datetime.strptime(date_str, '%Y%m%d').date()
|
|
||||||
except:
|
|
||||||
return datetime.min.date()
|
|
||||||
|
|
||||||
|
# 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
|
row_num = 2
|
||||||
for item in sorted(self.delivery_schedules, key=lambda x: parse_date(x.get('Datum', ''))):
|
for data in prepared_data:
|
||||||
|
item = data['item']
|
||||||
|
|
||||||
# Get week number from date
|
# Get week number from date
|
||||||
week_num = self.get_week_number(item.get('Datum', ''))
|
week_num = self.get_week_number(item.get('Datum', ''))
|
||||||
|
|
||||||
@@ -560,7 +603,7 @@ class EDIDelforCumminsParser:
|
|||||||
try:
|
try:
|
||||||
quantity = float(quantity) if quantity else 0
|
quantity = float(quantity) if quantity else 0
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
quantity = item.get('Množství', '')
|
quantity = 0
|
||||||
|
|
||||||
# Format week number as number
|
# Format week number as number
|
||||||
try:
|
try:
|
||||||
@@ -568,99 +611,139 @@ class EDIDelforCumminsParser:
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
week_num = 0
|
week_num = 0
|
||||||
|
|
||||||
# Format part number as number if possible
|
# Get part number
|
||||||
part_number = item.get('Položka', '')
|
part_number = item.get('Položka', '')
|
||||||
try:
|
|
||||||
if str(part_number).strip(): # Only convert if not empty
|
|
||||||
part_number = int(part_number)
|
|
||||||
else:
|
|
||||||
part_number = None
|
|
||||||
except (ValueError, AttributeError, TypeError):
|
|
||||||
part_number = str(part_number) # Keep as string if can't convert to int
|
|
||||||
|
|
||||||
# Format release as number if possible
|
# Get SCC description
|
||||||
release = item.get('Release', '')
|
scc = item.get('SCC', '')
|
||||||
try:
|
scc_desc = self.get_scc_description(str(scc)) if scc else ''
|
||||||
if str(release).strip(): # Only convert if not empty
|
|
||||||
release = int(release)
|
|
||||||
else:
|
|
||||||
release = None
|
|
||||||
except (ValueError, AttributeError, TypeError):
|
|
||||||
release = str(release) # Keep as string if can't convert to int
|
|
||||||
|
|
||||||
# Add week number and date in the first two columns
|
# Get delivery location
|
||||||
ws.cell(row=row_num, column=1, value=week_num)
|
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
|
||||||
|
|
||||||
# Format date as Excel date
|
# 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', '')
|
date_str = item.get('Datum', '')
|
||||||
try:
|
try:
|
||||||
if date_str:
|
if date_str:
|
||||||
date_obj = datetime.strptime(date_str, '%d.%m.%Y')
|
if '.' in date_str:
|
||||||
ws.cell(row=row_num, column=2, value=date_obj).number_format = 'DD.MM.YYYY'
|
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:
|
else:
|
||||||
ws.cell(row=row_num, column=2, value='')
|
cell = ws.cell(row=row_num, column=2, value='')
|
||||||
except (ValueError, TypeError):
|
except:
|
||||||
ws.cell(row=row_num, column=2, value=date_str)
|
cell = ws.cell(row=row_num, column=2, value=date_str)
|
||||||
|
|
||||||
# Part number - format as number if possible
|
# 3. Týden (week number) - not colored
|
||||||
if part_number is not None and part_number != '':
|
cell = ws.cell(row=row_num, column=3, value=week_num)
|
||||||
if isinstance(part_number, (int, float)):
|
cell.number_format = '0'
|
||||||
ws.cell(row=row_num, column=3, value=part_number).number_format = '0'
|
|
||||||
|
# 4. Množství (quantity as number) - not colored
|
||||||
|
try:
|
||||||
|
if isinstance(quantity, (int, float)):
|
||||||
|
qty_value = float(quantity)
|
||||||
else:
|
else:
|
||||||
ws.cell(row=row_num, column=3, value=str(part_number)).number_format = '@' # Text format if not a number
|
qty_str = str(quantity).strip().replace("'", "")
|
||||||
else:
|
qty_value = float(qty_str) if qty_str.replace('.', '', 1).isdigit() else 0.0
|
||||||
ws.cell(row=row_num, column=3, value='')
|
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'
|
||||||
|
|
||||||
# Format text columns as text
|
# 5. SCC (as text) - not colored
|
||||||
ws.cell(row=row_num, column=4, value=str(item.get('Popis', ''))).number_format = '@' # Popis as text
|
cell = ws.cell(row=row_num, column=5, value=str(scc_desc))
|
||||||
ws.cell(row=row_num, column=5, value=quantity) # Quantity as number
|
cell.number_format = '@'
|
||||||
ws.cell(row=row_num, column=6, value=str(item.get('Typ', ''))).number_format = '@' # Typ as text
|
|
||||||
ws.cell(row=row_num, column=7, value=str(item.get('SCC', ''))).number_format = '@' # SCC as text
|
|
||||||
|
|
||||||
# Release - format as number if possible
|
# 6. Dodací místo (delivery address as text) - not colored
|
||||||
if release is not None and release != '':
|
cell = ws.cell(row=row_num, column=6, value=delivery_location)
|
||||||
if isinstance(release, (int, float)):
|
cell.number_format = '@'
|
||||||
ws.cell(row=row_num, column=8, value=release).number_format = '0'
|
|
||||||
else:
|
|
||||||
ws.cell(row=row_num, column=8, value=str(release)).number_format = '@' # Text format if not a number
|
|
||||||
else:
|
|
||||||
ws.cell(row=row_num, column=8, value='')
|
|
||||||
|
|
||||||
# Get delivery location - ensure we have a non-empty string
|
|
||||||
dodaci_misto = str(self.partner_info.get('Dodací adresa', '') or '').strip()
|
|
||||||
ws.cell(row=row_num, column=9, value=dodaci_misto).number_format = '@' # Dodací místo as text
|
|
||||||
row_num += 1
|
row_num += 1
|
||||||
|
|
||||||
# Apply number formatting to numeric columns
|
# Apply number formatting to numeric columns
|
||||||
for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
|
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
|
# 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 row[0].value is not None and row[0].value != '': # Column 1 (0-based index 0)
|
||||||
if isinstance(row[0].value, (int, float)):
|
if isinstance(row[0].value, (int, float)):
|
||||||
row[0].number_format = '0'
|
row[0].number_format = '0'
|
||||||
|
|
||||||
# Format quantity (column 5) as number with no decimal places
|
|
||||||
if 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'
|
|
||||||
|
|
||||||
# Format part number (column 3) as number with no decimal places if it's a number
|
# Format part number (column 3) as number with no decimal places if it's a number
|
||||||
if row[2].value is not None and row[2].value != '': # Column 3 (0-based index 2)
|
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)):
|
if isinstance(row[2].value, (int, float)):
|
||||||
row[2].number_format = '0'
|
row[2].number_format = '0'
|
||||||
|
|
||||||
# Format release (column 8) as number with no decimal places if it's a number
|
# Format quantity (column 4) as number with no decimal places
|
||||||
if row[7].value is not None and row[7].value != '': # Column 8 (0-based index 7)
|
if len(row) > 4 and row[4].value is not None and row[4].value != '': # Column 5 (0-based index 4)
|
||||||
if isinstance(row[7].value, (int, float)):
|
if isinstance(row[4].value, (int, float)):
|
||||||
row[7].number_format = '0'
|
row[4].number_format = '0'
|
||||||
|
|
||||||
# Auto-adjust column widths
|
# 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:
|
for col in ws.columns:
|
||||||
max_length = 0
|
max_length = 0
|
||||||
column = col[0].column_letter
|
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:
|
for cell in col:
|
||||||
try:
|
try:
|
||||||
# For dates, use the formatted string length
|
# For dates, use the formatted string length
|
||||||
if cell.is_date:
|
if hasattr(cell, 'is_date') and cell.is_date:
|
||||||
cell_value = cell.value.strftime('%d.%m.%Y') if cell.value else ''
|
cell_value = cell.value.strftime('%d.%m.%Y') if cell.value else ''
|
||||||
else:
|
else:
|
||||||
cell_value = str(cell.value) if cell.value is not None else ''
|
cell_value = str(cell.value) if cell.value is not None else ''
|
||||||
@@ -669,8 +752,17 @@ class EDIDelforCumminsParser:
|
|||||||
max_length = len(cell_value)
|
max_length = len(cell_value)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
adjusted_width = (max_length + 2)
|
|
||||||
ws.column_dimensions[column].width = min(adjusted_width, 30)
|
# 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
|
# Add a summary sheet with just week and quantity
|
||||||
ws_summary = wb.create_sheet("Přehled")
|
ws_summary = wb.create_sheet("Přehled")
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ class EDIUnifiedParser:
|
|||||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||||
|
|
||||||
def load_file(self):
|
def load_file(self):
|
||||||
|
initial_dir = r"M:\APLIKACE\Edirex\INArchiv"
|
||||||
filepath = filedialog.askopenfilename(
|
filepath = filedialog.askopenfilename(
|
||||||
title="Vyberte EDI soubor",
|
title="Vyberte EDI soubor",
|
||||||
|
initialdir=initial_dir if os.path.exists(initial_dir) else ".",
|
||||||
filetypes=[("EDI files", "*.edi"), ("All files", "*.*")]
|
filetypes=[("EDI files", "*.edi"), ("All files", "*.*")]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+120
-108
@@ -161,18 +161,18 @@ class EDIDelforParser:
|
|||||||
|
|
||||||
def parse_edi_file(self, content):
|
def parse_edi_file(self, content):
|
||||||
"""Parsuje EDI DELFOR soubor"""
|
"""Parsuje EDI DELFOR soubor"""
|
||||||
lines = content.strip().split("'")
|
lines = [line.strip() for line in content.strip().split("'") if line.strip()]
|
||||||
|
|
||||||
# Reset dat
|
# Reset dat
|
||||||
self.header_info = {}
|
self.header_info = {}
|
||||||
self.partner_info = {}
|
self.partner_info = {}
|
||||||
self.delivery_schedules = []
|
self.delivery_schedules = []
|
||||||
|
|
||||||
current_delivery = {}
|
i = 0
|
||||||
|
while i < len(lines):
|
||||||
for line in lines:
|
line = lines[i]
|
||||||
line = line.strip()
|
|
||||||
if not line:
|
if not line:
|
||||||
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# UNB - Interchange header
|
# UNB - Interchange header
|
||||||
@@ -180,29 +180,16 @@ class EDIDelforParser:
|
|||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 5:
|
if len(parts) >= 5:
|
||||||
self.header_info['Odesílatel'] = parts[2]
|
self.header_info['Odesílatel'] = parts[2]
|
||||||
# Uložíme kód příjemce, název doplníme později z NAD segmentu
|
|
||||||
self.header_info['Příjemce_kód'] = parts[3]
|
self.header_info['Příjemce_kód'] = parts[3]
|
||||||
self.header_info['Datum/Čas'] = self.parse_edi_datetime(parts[4])
|
self.header_info['Datum/Čas'] = self.parse_edi_datetime(parts[4])
|
||||||
|
i += 1
|
||||||
|
|
||||||
# BGM - Beginning of message
|
# BGM - Beginning of message
|
||||||
elif line.startswith('BGM'):
|
elif line.startswith('BGM'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 3:
|
if len(parts) >= 3:
|
||||||
self.header_info['Číslo zprávy'] = parts[2]
|
self.header_info['Číslo zprávy'] = parts[2]
|
||||||
|
i += 1
|
||||||
# DTM - Date/time
|
|
||||||
elif line.startswith('DTM'):
|
|
||||||
parts = line.split('+')
|
|
||||||
if len(parts) >= 2:
|
|
||||||
dtm_parts = parts[1].split(':')
|
|
||||||
if len(dtm_parts) >= 3:
|
|
||||||
date_formatted = self.parse_date(dtm_parts[1], dtm_parts[2])
|
|
||||||
if dtm_parts[0] == '137':
|
|
||||||
self.header_info['Datum dokumentu'] = date_formatted
|
|
||||||
elif dtm_parts[0] == '63':
|
|
||||||
current_delivery['Datum do'] = date_formatted
|
|
||||||
elif dtm_parts[0] == '64':
|
|
||||||
current_delivery['Datum od'] = date_formatted
|
|
||||||
|
|
||||||
# NAD - Name and address
|
# NAD - Name and address
|
||||||
elif line.startswith('NAD'):
|
elif line.startswith('NAD'):
|
||||||
@@ -210,15 +197,13 @@ class EDIDelforParser:
|
|||||||
if len(parts) >= 3:
|
if len(parts) >= 3:
|
||||||
role = parts[1]
|
role = parts[1]
|
||||||
code = parts[2] if len(parts) > 2 else ''
|
code = parts[2] if len(parts) > 2 else ''
|
||||||
|
|
||||||
# Název společnosti je v parts[4] (index 4)
|
|
||||||
name = parts[4] if len(parts) > 4 else ''
|
name = parts[4] if len(parts) > 4 else ''
|
||||||
|
|
||||||
# Adresa začíná od parts[5]
|
# Process address parts
|
||||||
address_parts = []
|
address_parts = []
|
||||||
for i in range(5, len(parts)):
|
for j in range(5, len(parts)):
|
||||||
if parts[i]: # Přidáme pouze neprázdné části
|
if parts[j]:
|
||||||
address_parts.append(parts[i])
|
address_parts.append(parts[j])
|
||||||
|
|
||||||
full_address = ', '.join(address_parts) if address_parts else ''
|
full_address = ', '.join(address_parts) if address_parts else ''
|
||||||
|
|
||||||
@@ -227,11 +212,9 @@ class EDIDelforParser:
|
|||||||
if full_address:
|
if full_address:
|
||||||
self.partner_info['Kupující'] += f", {full_address}"
|
self.partner_info['Kupující'] += f", {full_address}"
|
||||||
elif role == 'SE':
|
elif role == 'SE':
|
||||||
# Zkontrolujeme, zda SE obsahuje kód příjemce z UNB
|
|
||||||
if code == self.header_info.get('Příjemce_kód', ''):
|
if code == self.header_info.get('Příjemce_kód', ''):
|
||||||
self.header_info['Příjemce'] = name
|
self.header_info['Příjemce'] = name
|
||||||
|
|
||||||
# Pro prodávajícího použijeme název + adresu
|
|
||||||
if full_address:
|
if full_address:
|
||||||
self.partner_info['Prodávající'] = f"{name}, {full_address}"
|
self.partner_info['Prodávající'] = f"{name}, {full_address}"
|
||||||
else:
|
else:
|
||||||
@@ -241,52 +224,77 @@ class EDIDelforParser:
|
|||||||
self.partner_info['Dodací adresa'] = f"{name}, {full_address}"
|
self.partner_info['Dodací adresa'] = f"{name}, {full_address}"
|
||||||
else:
|
else:
|
||||||
self.partner_info['Dodací adresa'] = name
|
self.partner_info['Dodací adresa'] = name
|
||||||
|
i += 1
|
||||||
|
|
||||||
# LIN - Line item
|
# LIN - Line item
|
||||||
elif line.startswith('LIN'):
|
elif line.startswith('LIN'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 4:
|
if len(parts) >= 4:
|
||||||
self.header_info['Číslo položky'] = parts[3]
|
self.header_info['Číslo položky'] = parts[3]
|
||||||
|
i += 1
|
||||||
|
|
||||||
# PIA - Product identification
|
# PIA - Product identification
|
||||||
elif line.startswith('PIA'):
|
elif line.startswith('PIA'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 3:
|
if len(parts) >= 3:
|
||||||
self.header_info['Kód produktu'] = parts[2]
|
self.header_info['Kód produktu'] = parts[2]
|
||||||
|
i += 1
|
||||||
|
|
||||||
# QTY - Quantity
|
# Handle delivery block (4 lines in specific order: QTY+113, SCC, DTM+63, DTM+64)
|
||||||
elif line.startswith('QTY'):
|
elif line.startswith('QTY+113'):
|
||||||
parts = line.split('+')
|
try:
|
||||||
if len(parts) >= 2:
|
# Create new delivery record
|
||||||
qty_parts = parts[1].split(':')
|
current_delivery = {}
|
||||||
if len(qty_parts) >= 3:
|
|
||||||
qty_type = qty_parts[0]
|
|
||||||
quantity = qty_parts[1]
|
|
||||||
unit = qty_parts[2]
|
|
||||||
|
|
||||||
if qty_type == '113': # Plánované množství k dodání
|
# 1. Process QTY+113 line (current line)
|
||||||
current_delivery['Množství'] = quantity
|
qty_parts = line.split('+')
|
||||||
current_delivery['Jednotka'] = unit
|
if len(qty_parts) >= 2:
|
||||||
|
qty_info = qty_parts[1].split(':')
|
||||||
|
if len(qty_info) >= 3:
|
||||||
|
current_delivery['Množství'] = qty_info[1]
|
||||||
|
current_delivery['Jednotka'] = qty_info[2]
|
||||||
current_delivery['Typ'] = 'Plánované množství'
|
current_delivery['Typ'] = 'Plánované množství'
|
||||||
elif qty_type == '70': # Minimální množství
|
|
||||||
current_delivery['Množství'] = quantity
|
|
||||||
current_delivery['Jednotka'] = unit
|
|
||||||
current_delivery['Typ'] = 'Minimální'
|
|
||||||
elif qty_type == '78': # Maximální množství
|
|
||||||
current_delivery['Množství'] = quantity
|
|
||||||
current_delivery['Jednotka'] = unit
|
|
||||||
current_delivery['Typ'] = 'Maximální'
|
|
||||||
|
|
||||||
# SCC - Scheduling conditions
|
# Move to next line
|
||||||
elif line.startswith('SCC'):
|
i += 1
|
||||||
parts = line.split('+')
|
if i >= len(lines):
|
||||||
if len(parts) >= 2:
|
break
|
||||||
current_delivery['SCC'] = parts[1]
|
|
||||||
|
|
||||||
# Pokud máme kompletní dodávku, přidáme ji
|
# 2. Process SCC line (next line)
|
||||||
if 'Datum od' in current_delivery and 'Množství' in current_delivery:
|
if lines[i].startswith('SCC'):
|
||||||
|
scc_parts = lines[i].split('+')
|
||||||
|
if len(scc_parts) >= 2:
|
||||||
|
current_delivery['SCC'] = scc_parts[1]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# 3. Process DTM+63 line (end date)
|
||||||
|
if i < len(lines) and lines[i].startswith('DTM+63'):
|
||||||
|
dtm_parts = lines[i].split('+')
|
||||||
|
if len(dtm_parts) >= 2:
|
||||||
|
dtm_info = dtm_parts[1].split(':')
|
||||||
|
if len(dtm_info) >= 3:
|
||||||
|
current_delivery['Datum do'] = self.parse_date(dtm_info[1], dtm_info[2])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# 4. Process DTM+64 line (start date)
|
||||||
|
if i < len(lines) and lines[i].startswith('DTM+64'):
|
||||||
|
dtm_parts = lines[i].split('+')
|
||||||
|
if len(dtm_parts) >= 2:
|
||||||
|
dtm_info = dtm_parts[1].split(':')
|
||||||
|
if len(dtm_info) >= 3:
|
||||||
|
current_delivery['Datum od'] = self.parse_date(dtm_info[1], dtm_info[2])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# Add completed delivery to schedules
|
||||||
|
if 'Množství' in current_delivery and 'Datum od' in current_delivery:
|
||||||
self.delivery_schedules.append(current_delivery.copy())
|
self.delivery_schedules.append(current_delivery.copy())
|
||||||
current_delivery = {'SCC': parts[1]} # Zachováme SCC pro další dodávky
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error processing delivery block: {e}")
|
||||||
|
i += 1 # Skip to next line on error
|
||||||
|
else:
|
||||||
|
# Skip any other lines we don't process
|
||||||
|
i += 1
|
||||||
|
|
||||||
def load_file(self, filepath):
|
def load_file(self, filepath):
|
||||||
"""Načte EDI soubor"""
|
"""Načte EDI soubor"""
|
||||||
@@ -408,90 +416,94 @@ class EDIDelforParser:
|
|||||||
ws = wb.active
|
ws = wb.active
|
||||||
ws.title = "Dodávky"
|
ws.title = "Dodávky"
|
||||||
|
|
||||||
# Hlavičky
|
# Hlavičky podle požadavku: datum, týden, množství, SCC, zbytek ad lib
|
||||||
headers = ["Týden", "Datum od", "Množství", "Typ", "SCC", "Dodací místo"]
|
headers = ["Datum", "Týden", "Množství", "SCC", "Dodací místo"]
|
||||||
for col_num, header in enumerate(headers, 1):
|
for col_num, header in enumerate(headers, 1):
|
||||||
cell = ws.cell(row=1, column=col_num, value=header)
|
cell = ws.cell(row=1, column=col_num, value=header)
|
||||||
cell.font = Font(bold=True)
|
cell.font = Font(bold=True)
|
||||||
cell.alignment = Alignment(horizontal='center')
|
cell.alignment = Alignment(horizontal='center')
|
||||||
|
|
||||||
|
# Připravíme data pro řazení
|
||||||
|
prepared_data = []
|
||||||
|
for delivery in self.delivery_schedules:
|
||||||
|
# Získáme položku (item) - pokud neexistuje, použijeme prázdný řetězec
|
||||||
|
item = delivery.get('Položka', '')
|
||||||
|
|
||||||
|
# Zpracujeme datum pro řazení
|
||||||
|
date_str = delivery.get('Datum od', '')
|
||||||
|
date_for_sort = None
|
||||||
|
if date_str:
|
||||||
|
try:
|
||||||
|
date_parts = date_str.split(' ')[0].split('.')
|
||||||
|
if len(date_parts) == 3:
|
||||||
|
date_for_sort = datetime(int(date_parts[2]), int(date_parts[1]), int(date_parts[0]))
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
prepared_data.append({
|
||||||
|
'item': item,
|
||||||
|
'date_for_sort': date_for_sort or datetime.max,
|
||||||
|
'delivery': delivery
|
||||||
|
})
|
||||||
|
|
||||||
|
# Seřadíme data podle položky a data
|
||||||
|
prepared_data.sort(key=lambda x: (x['item'] or '', x['date_for_sort']))
|
||||||
|
|
||||||
# Data
|
# Data
|
||||||
row_num = 2
|
row_num = 2
|
||||||
for delivery in self.delivery_schedules:
|
for item_data in prepared_data:
|
||||||
|
delivery = item_data['delivery']
|
||||||
date_from = delivery.get('Datum od', '')
|
date_from = delivery.get('Datum od', '')
|
||||||
week_num = self.get_week_number(date_from) if date_from else ""
|
week_num = self.get_week_number(date_from) if date_from else ""
|
||||||
scc_code = delivery.get('SCC', '')
|
scc_code = delivery.get('SCC', '')
|
||||||
scc_desc = self.get_scc_description(scc_code)
|
scc_desc = self.get_scc_description(scc_code)
|
||||||
|
|
||||||
# Format week number as number
|
# Datum (sloupec 1)
|
||||||
try:
|
|
||||||
week_num = int(week_num) if week_num else 0
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
week_num = 0
|
|
||||||
|
|
||||||
# Format quantity as number, removing any leading quotes
|
|
||||||
quantity = delivery.get('Množství', '')
|
|
||||||
if isinstance(quantity, str):
|
|
||||||
quantity = quantity.strip("'")
|
|
||||||
try:
|
|
||||||
quantity = float(quantity) if quantity else 0
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
quantity = delivery.get('Množství', '')
|
|
||||||
|
|
||||||
# Format SCC as number if possible
|
|
||||||
scc = delivery.get('SCC', '')
|
|
||||||
try:
|
|
||||||
scc = int(scc) if scc.strip() else ''
|
|
||||||
except (ValueError, AttributeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Add week number
|
|
||||||
ws.cell(row=row_num, column=1, value=week_num)
|
|
||||||
|
|
||||||
# Format date as Excel date - handle both with and without time
|
|
||||||
date_from = delivery.get('Datum od', '')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if date_from:
|
if date_from:
|
||||||
# Remove time part if present
|
# Remove time part if present
|
||||||
date_from = date_from.split(' ')[0]
|
date_from = date_from.split(' ')[0]
|
||||||
date_from_obj = datetime.strptime(date_from, '%d.%m.%Y')
|
date_from_obj = datetime.strptime(date_from, '%d.%m.%Y')
|
||||||
ws.cell(row=row_num, column=2, value=date_from_obj).number_format = 'DD.MM.YYYY'
|
ws.cell(row=row_num, column=1, value=date_from_obj).number_format = 'DD.MM.YYYY'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Log error silently
|
|
||||||
ws.cell(row=row_num, column=2, value=date_from.split(' ')[0] if date_from else '')
|
ws.cell(row=row_num, column=2, value=date_from.split(' ')[0] if date_from else '')
|
||||||
|
|
||||||
# Add other data with proper formatting
|
# Týden (sloupec 2)
|
||||||
# Format quantity as number
|
|
||||||
try:
|
try:
|
||||||
if isinstance(quantity, (int, float)):
|
week_num = int(week_num) if week_num else 0
|
||||||
qty_value = float(quantity)
|
ws.cell(row=row_num, column=2, value=week_num).number_format = '0'
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
ws.cell(row=row_num, column=3, value=0)
|
||||||
|
|
||||||
|
# Množství (sloupec 3)
|
||||||
|
quantity = delivery.get('Množství', '')
|
||||||
|
try:
|
||||||
|
if isinstance(quantity, str):
|
||||||
|
quantity = quantity.strip("'")
|
||||||
|
qty_value = float(quantity) if quantity else 0.0
|
||||||
else:
|
else:
|
||||||
qty_str = str(quantity).strip().replace("'", "")
|
qty_value = float(quantity) if quantity is not None else 0.0
|
||||||
qty_value = float(qty_str) if qty_str.replace('.', '', 1).isdigit() else 0.0
|
ws.cell(row=row_num, column=3, value=qty_value).number_format = '0'
|
||||||
ws.cell(row=row_num, column=3, value=qty_value)
|
except (ValueError, TypeError):
|
||||||
except (ValueError, AttributeError):
|
ws.cell(row=row_num, column=4, value=0.0).number_format = '0'
|
||||||
ws.cell(row=row_num, column=3, value=0.0)
|
|
||||||
|
|
||||||
# Format text columns as text
|
# SCC (sloupec 4)
|
||||||
ws.cell(row=row_num, column=4, value=str(delivery.get('Typ', ''))).number_format = '@' # Typ as text
|
scc_desc = self.get_scc_description(str(delivery.get('SCC', '')))
|
||||||
|
ws.cell(row=row_num, column=4, value=str(scc_desc)).number_format = '@'
|
||||||
|
|
||||||
# Use SCC description instead of code and format as text
|
# Dodací místo (sloupec 5)
|
||||||
scc_desc = self.get_scc_description(str(scc))
|
ws.cell(row=row_num, column=5, value=str(self.partner_info.get('Dodací adresa', '') or 'XTREME PRESSURE INJECTION JUAREZ, REC LOC 372, EL PASO, 79927')).number_format = '@'
|
||||||
ws.cell(row=row_num, column=5, value=str(scc_desc)).number_format = '@' # SCC as text
|
|
||||||
|
|
||||||
# Format delivery location as text
|
|
||||||
ws.cell(row=row_num, column=6, value=str(self.partner_info.get('Dodací adresa', '') or 'XTREME PRESSURE INJECTION JUAREZ, REC LOC 372, EL PASO, 79927')).number_format = '@'
|
|
||||||
row_num += 1
|
row_num += 1
|
||||||
|
|
||||||
# Apply number formatting to numeric columns
|
# Apply number formatting to numeric columns
|
||||||
for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
|
for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
|
||||||
# Format quantity column (column 3) as number with no decimal places
|
# Format quantity column (column 2) as number with no decimal places
|
||||||
if row[2].value is not None: # Column 3 (0-based index 2)
|
if row[2].value is not None: # Column 3 (0-based index 2)
|
||||||
row[2].number_format = '0'
|
row[2].number_format = '0'
|
||||||
# Format week number column (column 1) as number with no decimal places
|
# Format week number column (column 1) as number with no decimal places
|
||||||
if row[0].value is not None: # Column 1 (0-based index 0)
|
if row[1].value is not None: # Column 2 (0-based index 1)
|
||||||
row[0].number_format = '0'
|
row[1].number_format = '0'
|
||||||
|
|
||||||
# Automatické přizpůsobení šířky sloupců
|
# Automatické přizpůsobení šířky sloupců
|
||||||
for col in ws.columns:
|
for col in ws.columns:
|
||||||
|
|||||||
+95
-105
@@ -126,60 +126,50 @@ class EDITrwkobParser:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def parse_edi_file(self, content):
|
def parse_edi_file(self, content):
|
||||||
lines = content.strip().split("'")
|
lines = [line.strip() for line in content.strip().split("'") if line.strip()]
|
||||||
self.header_info = {}
|
self.header_info = {}
|
||||||
self.partner_info = {}
|
self.partner_info = {}
|
||||||
self.delivery_schedules = []
|
self.delivery_schedules = []
|
||||||
current_delivery = {}
|
|
||||||
|
|
||||||
# Helper function to add a delivery if it's complete
|
i = 0
|
||||||
def add_delivery_if_complete(delivery):
|
while i < len(lines):
|
||||||
if all(key in delivery for key in ['Datum od', 'Množství', 'Typ', 'SCC']):
|
line = lines[i]
|
||||||
# Add the delivery - we'll handle duplicates later
|
|
||||||
self.delivery_schedules.append(delivery.copy())
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
line = line.strip()
|
|
||||||
if not line:
|
if not line:
|
||||||
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# UNB - Interchange header
|
||||||
if line.startswith('UNB'):
|
if line.startswith('UNB'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 5:
|
if len(parts) >= 5:
|
||||||
self.header_info['Odesílatel'] = parts[2]
|
self.header_info['Odesílatel'] = parts[2]
|
||||||
self.header_info['Příjemce_kód'] = parts[3]
|
self.header_info['Příjemce_kód'] = parts[3]
|
||||||
self.header_info['Datum/Čas'] = self.parse_edi_datetime(parts[4])
|
self.header_info['Datum/Čas'] = self.parse_edi_datetime(parts[4])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# BGM - Beginning of message
|
||||||
elif line.startswith('BGM'):
|
elif line.startswith('BGM'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 3:
|
if len(parts) >= 3:
|
||||||
self.header_info['Číslo zprávy'] = parts[2]
|
self.header_info['Číslo zprávy'] = parts[2]
|
||||||
|
i += 1
|
||||||
|
|
||||||
elif line.startswith('DTM'):
|
# NAD - Name and address
|
||||||
parts = line.split('+')
|
|
||||||
if len(parts) >= 2:
|
|
||||||
dtm_parts = parts[1].split(':')
|
|
||||||
if len(dtm_parts) >= 2:
|
|
||||||
date_formatted = self.parse_date(dtm_parts[1], dtm_parts[2] if len(dtm_parts) > 2 else '')
|
|
||||||
if dtm_parts[0] == '137':
|
|
||||||
self.header_info['Datum dokumentu'] = date_formatted
|
|
||||||
elif dtm_parts[0] == '64': # Start date
|
|
||||||
current_delivery['Datum od'] = date_formatted
|
|
||||||
elif dtm_parts[0] == '63': # End date (we'll use this if no start date)
|
|
||||||
if 'Datum od' not in current_delivery:
|
|
||||||
current_delivery['Datum od'] = date_formatted
|
|
||||||
|
|
||||||
elif line.startswith('NAD'):
|
elif line.startswith('NAD'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 3:
|
if len(parts) >= 3:
|
||||||
role = parts[1]
|
role = parts[1]
|
||||||
code = parts[2]
|
code = parts[2]
|
||||||
name = parts[4] if len(parts) > 4 else ''
|
name = parts[4] if len(parts) > 4 else ''
|
||||||
|
|
||||||
|
# Process address parts
|
||||||
address_parts = []
|
address_parts = []
|
||||||
for i in range(5, len(parts)):
|
for j in range(5, len(parts)):
|
||||||
if parts[i]:
|
if parts[j]:
|
||||||
address_parts.append(parts[i])
|
address_parts.append(parts[j])
|
||||||
|
|
||||||
full_address = ', '.join(address_parts) if address_parts else ''
|
full_address = ', '.join(address_parts) if address_parts else ''
|
||||||
|
|
||||||
if role == 'BY':
|
if role == 'BY':
|
||||||
self.partner_info['Kupující'] = name if name else code
|
self.partner_info['Kupující'] = name if name else code
|
||||||
if full_address:
|
if full_address:
|
||||||
@@ -195,79 +185,77 @@ class EDITrwkobParser:
|
|||||||
self.partner_info['Dodací adresa'] = f"{name if name else code}, {full_address}"
|
self.partner_info['Dodací adresa'] = f"{name if name else code}, {full_address}"
|
||||||
else:
|
else:
|
||||||
self.partner_info['Dodací adresa'] = name if name else code
|
self.partner_info['Dodací adresa'] = name if name else code
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# LIN - Line item
|
||||||
elif line.startswith('LIN'):
|
elif line.startswith('LIN'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 4:
|
if len(parts) >= 4:
|
||||||
self.header_info['Číslo položky'] = parts[3]
|
self.header_info['Číslo položky'] = parts[3]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# PIA - Product identification
|
||||||
elif line.startswith('PIA'):
|
elif line.startswith('PIA'):
|
||||||
parts = line.split('+')
|
parts = line.split('+')
|
||||||
if len(parts) >= 3:
|
if len(parts) >= 3:
|
||||||
self.header_info['Kód produktu'] = parts[2]
|
self.header_info['Kód produktu'] = parts[2]
|
||||||
|
i += 1
|
||||||
|
|
||||||
elif line.startswith('QTY'):
|
# Handle delivery block (4 lines in specific order: QTY+113, SCC, DTM+63, DTM+64)
|
||||||
parts = line.split('+')
|
elif line.startswith('QTY+113'):
|
||||||
if len(parts) >= 2:
|
try:
|
||||||
qty_parts = parts[1].split(':')
|
# Create new delivery record
|
||||||
if qty_parts:
|
current_delivery = {}
|
||||||
qty_type = qty_parts[0]
|
|
||||||
quantity = qty_parts[1] if len(qty_parts) > 1 else ''
|
|
||||||
unit = qty_parts[2] if len(qty_parts) > 2 else 'PCE' # Default to PCE if not specified
|
|
||||||
|
|
||||||
# Only process QTY if we have a date and SCC
|
# 1. Process QTY+113 line (current line)
|
||||||
if 'Datum od' in current_delivery and 'SCC' in current_delivery:
|
qty_parts = line.split('+')
|
||||||
if qty_type in ['113', '12']: # Plánované množství k dodání
|
if len(qty_parts) >= 2:
|
||||||
current_delivery['Množství'] = quantity
|
qty_info = qty_parts[1].split(':')
|
||||||
current_delivery['Jednotka'] = unit
|
if len(qty_info) >= 3:
|
||||||
current_delivery['Typ'] = 'Plánované množství'
|
current_delivery['Množství'] = qty_info[1]
|
||||||
add_delivery_if_complete(current_delivery)
|
current_delivery['Jednotka'] = qty_info[2] if len(qty_info) > 2 else 'PCE'
|
||||||
|
current_delivery['Typ'] = 'Plánované množství'
|
||||||
|
|
||||||
elif qty_type == '70':
|
# Move to next line
|
||||||
current_delivery['Množství'] = quantity
|
i += 1
|
||||||
current_delivery['Jednotka'] = unit
|
if i >= len(lines):
|
||||||
current_delivery['Typ'] = 'Minimální'
|
break
|
||||||
add_delivery_if_complete(current_delivery)
|
|
||||||
|
|
||||||
elif qty_type == '78':
|
# 2. Process SCC line (next line)
|
||||||
current_delivery['Množství'] = quantity
|
if i < len(lines) and lines[i].startswith('SCC'):
|
||||||
current_delivery['Jednotka'] = unit
|
scc_parts = lines[i].split('+')
|
||||||
current_delivery['Typ'] = 'Maximální'
|
if len(scc_parts) >= 2:
|
||||||
add_delivery_if_complete(current_delivery)
|
current_delivery['SCC'] = scc_parts[1]
|
||||||
|
i += 1
|
||||||
|
|
||||||
elif line.startswith('SCC'):
|
# 3. Process DTM+63 line (end date)
|
||||||
# Add the previous delivery if it's complete
|
if i < len(lines) and lines[i].startswith('DTM+63'):
|
||||||
if all(key in current_delivery for key in ['Datum od', 'Množství', 'Typ', 'SCC']):
|
dtm_parts = lines[i].split('+')
|
||||||
add_delivery_if_complete(current_delivery)
|
if len(dtm_parts) >= 2:
|
||||||
|
dtm_info = dtm_parts[1].split(':')
|
||||||
|
if len(dtm_info) >= 3:
|
||||||
|
current_delivery['Datum do'] = self.parse_date(dtm_info[1], dtm_info[2])
|
||||||
|
i += 1
|
||||||
|
|
||||||
parts = line.split('+')
|
# 4. Process DTM+64 line (start date)
|
||||||
if len(parts) >= 2:
|
if i < len(lines) and lines[i].startswith('DTM+64'):
|
||||||
# Start a new delivery with the SCC code
|
dtm_parts = lines[i].split('+')
|
||||||
current_delivery = {'SCC': parts[1]}
|
if len(dtm_parts) >= 2:
|
||||||
|
dtm_info = dtm_parts[1].split(':')
|
||||||
|
if len(dtm_info) >= 3:
|
||||||
|
current_delivery['Datum od'] = self.parse_date(dtm_info[1], dtm_info[2])
|
||||||
|
i += 1
|
||||||
|
|
||||||
# Handle end of delivery schedule
|
# Add completed delivery to schedules
|
||||||
elif line.startswith('UNS+S'):
|
if 'Množství' in current_delivery and 'Datum od' in current_delivery:
|
||||||
if all(key in current_delivery for key in ['Datum od', 'Množství', 'Typ', 'SCC']):
|
self.delivery_schedules.append(current_delivery.copy())
|
||||||
add_delivery_if_complete(current_delivery)
|
|
||||||
|
|
||||||
# After processing all lines, remove exact duplicates
|
except Exception as e:
|
||||||
unique_deliveries = []
|
print(f"Error processing delivery block: {e}")
|
||||||
seen = set()
|
i += 1 # Skip to next line on error
|
||||||
for delivery in self.delivery_schedules:
|
else:
|
||||||
# Create a unique key based on all fields
|
# Skip any other lines we don't process
|
||||||
delivery_key = (
|
i += 1
|
||||||
delivery.get('Datum od', ''),
|
|
||||||
delivery.get('Množství', ''),
|
|
||||||
delivery.get('Typ', ''),
|
|
||||||
delivery.get('SCC', ''),
|
|
||||||
delivery.get('Jednotka', '')
|
|
||||||
)
|
|
||||||
if delivery_key not in seen:
|
|
||||||
seen.add(delivery_key)
|
|
||||||
unique_deliveries.append(delivery)
|
|
||||||
|
|
||||||
# Replace the delivery schedules with the deduplicated list
|
|
||||||
self.delivery_schedules = unique_deliveries
|
|
||||||
|
|
||||||
def display_data(self):
|
def display_data(self):
|
||||||
self.info_text.delete(1.0, tk.END)
|
self.info_text.delete(1.0, tk.END)
|
||||||
@@ -362,13 +350,13 @@ class EDITrwkobParser:
|
|||||||
return scc_mapping.get(scc_code, f'Neznámý kód: {scc_code}')
|
return scc_mapping.get(scc_code, f'Neznámý kód: {scc_code}')
|
||||||
|
|
||||||
def export_to_excel(self):
|
def export_to_excel(self):
|
||||||
"""Export delivery data to Excel with calendar weeks, sorted chronologically and without duplicates"""
|
"""Export delivery data to Excel with requested column order and sorting"""
|
||||||
if not self.delivery_schedules:
|
if not self.delivery_schedules:
|
||||||
messagebox.showwarning("Upozornění", "Žádná data k exportu")
|
messagebox.showwarning("Upozornění", "Žádná data k exportu")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Process all deliveries without deduplication
|
# Process all deliveries
|
||||||
processed_deliveries = []
|
processed_deliveries = []
|
||||||
|
|
||||||
for delivery in self.delivery_schedules:
|
for delivery in self.delivery_schedules:
|
||||||
@@ -386,31 +374,34 @@ class EDITrwkobParser:
|
|||||||
# Get delivery details
|
# Get delivery details
|
||||||
quantity = delivery.get('Množství', '').strip("'")
|
quantity = delivery.get('Množství', '').strip("'")
|
||||||
scc_code = delivery.get('SCC', '')
|
scc_code = delivery.get('SCC', '')
|
||||||
|
item = delivery.get('Položka', '') # Get item number if available
|
||||||
|
|
||||||
# Store with date object and original delivery for sorting
|
# Store with item, date, and original delivery for sorting
|
||||||
processed_deliveries.append((date_obj, {
|
processed_deliveries.append({
|
||||||
|
'item': item,
|
||||||
|
'date_obj': date_obj,
|
||||||
'date_str': date_str,
|
'date_str': date_str,
|
||||||
'quantity': quantity,
|
'quantity': quantity,
|
||||||
'type': delivery_type,
|
'type': delivery_type,
|
||||||
'scc_code': scc_code,
|
'scc_code': scc_code,
|
||||||
'scc_desc': self.get_scc_description(scc_code),
|
'scc_desc': self.get_scc_description(scc_code),
|
||||||
'delivery': delivery
|
'delivery': delivery
|
||||||
}))
|
})
|
||||||
|
|
||||||
except (ValueError, TypeError) as e:
|
except (ValueError, TypeError) as e:
|
||||||
print(f"Chyba při zpracování data: {date_str}, {e}")
|
print(f"Chyba při zpracování data: {date_str}, {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Sort by date (earliest first)
|
# Sort by item and then by date
|
||||||
processed_deliveries.sort(key=lambda x: x[0])
|
processed_deliveries.sort(key=lambda x: (str(x['item'] or ''), x['date_obj']))
|
||||||
|
|
||||||
# Create Excel workbook and worksheet
|
# Create Excel workbook and worksheet
|
||||||
wb = openpyxl.Workbook()
|
wb = openpyxl.Workbook()
|
||||||
ws = wb.active
|
ws = wb.active
|
||||||
ws.title = "Dodávky"
|
ws.title = "Dodávky"
|
||||||
|
|
||||||
# Headers
|
# Headers in requested order: datum, týden, množství, SCC, dodací místo
|
||||||
headers = ["Týden", "Datum", "Množství", "Typ", "SCC", "Dodací místo"]
|
headers = ["Datum", "Týden", "Množství", "SCC", "Dodací místo"]
|
||||||
for col_num, header in enumerate(headers, 1):
|
for col_num, header in enumerate(headers, 1):
|
||||||
cell = ws.cell(row=1, column=col_num, value=header)
|
cell = ws.cell(row=1, column=col_num, value=header)
|
||||||
cell.font = Font(bold=True)
|
cell.font = Font(bold=True)
|
||||||
@@ -418,32 +409,31 @@ class EDITrwkobParser:
|
|||||||
|
|
||||||
# Data
|
# Data
|
||||||
row_num = 2
|
row_num = 2
|
||||||
for date_obj, delivery_data in processed_deliveries:
|
for delivery_data in processed_deliveries:
|
||||||
# Add week number (ISO week)
|
# 1. Datum (date) - formatted
|
||||||
ws.cell(row=row_num, column=1, value=date_obj.isocalendar()[1])
|
ws.cell(row=row_num, column=1, value=delivery_data['date_obj']).number_format = 'DD.MM.YYYY'
|
||||||
|
|
||||||
# Add date with proper Excel formatting
|
# 2. Týden (week number) - as number
|
||||||
ws.cell(row=row_num, column=2, value=date_obj).number_format = 'DD.MM.YYYY'
|
ws.cell(row=row_num, column=2, value=delivery_data['date_obj'].isocalendar()[1])
|
||||||
|
|
||||||
# Add quantity as number
|
# 3. Množství (quantity) - as number
|
||||||
try:
|
try:
|
||||||
quantity = float(delivery_data['quantity']) if delivery_data['quantity'] else 0
|
quantity = float(delivery_data['quantity']) if delivery_data['quantity'] else 0
|
||||||
ws.cell(row=row_num, column=3, value=quantity)
|
ws.cell(row=row_num, column=3, value=quantity).number_format = '0'
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
ws.cell(row=row_num, column=3, value=delivery_data['quantity'])
|
ws.cell(row=row_num, column=3, value=delivery_data['quantity']).number_format = '0'
|
||||||
|
|
||||||
# Add type and SCC description as text
|
# 4. SCC - as text
|
||||||
ws.cell(row=row_num, column=4, value=delivery_data['type']).number_format = '@'
|
ws.cell(row=row_num, column=4, value=delivery_data['scc_desc']).number_format = '@'
|
||||||
ws.cell(row=row_num, column=5, value=delivery_data['scc_desc']).number_format = '@'
|
|
||||||
|
|
||||||
# Add delivery address
|
# 5. Dodací místo (delivery address) - as text
|
||||||
delivery_address = self.partner_info.get('Dodací adresa', '') or 'XTREME PRESSURE INJECTION JUAREZ, REC LOC 372, EL PASO, 79927'
|
delivery_address = self.partner_info.get('Dodací adresa', '') or 'XTREME PRESSURE INJECTION JUAREZ, REC LOC 372, EL PASO, 79927'
|
||||||
ws.cell(row=row_num, column=6, value=delivery_address).number_format = '@'
|
ws.cell(row=row_num, column=5, value=delivery_address).number_format = '@'
|
||||||
|
|
||||||
row_num += 1
|
row_num += 1
|
||||||
|
|
||||||
# Apply number formatting to numeric columns
|
# Apply number formatting to numeric columns
|
||||||
for col in [1, 3]: # Only format week number and quantity columns
|
for col in [2]: # Only format week number column (quantity is already formatted)
|
||||||
for row in ws.iter_rows(min_row=2, min_col=col, max_col=col):
|
for row in ws.iter_rows(min_row=2, min_col=col, max_col=col):
|
||||||
for cell in row:
|
for cell in row:
|
||||||
if isinstance(cell.value, (int, float)):
|
if isinstance(cell.value, (int, float)):
|
||||||
|
|||||||
Reference in New Issue
Block a user