dotfiles/VSCodium/User/History/-2f7fe65f/Td2J.py
2026-06-19 14:29:55 +02:00

131 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Script to populate an ODS template with data extracted from a source Excel file.
The script performs the following steps:
1. Reads the source Excel file "Production Order (mrp.production).xlsx".
2. Extracts a serial number suffix from column B where a cell contains "FA-".
3. Finds specific component rows (Barebone, GPU, RAM, CPU, SSD, RAID) and copies the value from the cell to the right of each.
4. Loads the ODS template "A4004_v3.0-260617.ods".
5. Writes the extracted values into designated ranges in the template.
6. Saves the modified template as a new ODS file named after the value in cell A2 of the source file.
Dependencies:
- pandas (for reading Excel files)
- openpyxl (Excel engine used by pandas)
- ezodf (for reading and writing ODS files)
Install them via:
pip install pandas openpyxl ezodf
Usage:
python populate_template.py
"""
import os
import sys
import pandas as pd
import ezodf
def find_fa_suffix(df: pd.DataFrame) -> str:
"""Search column B (index 1) for a cell containing "FA-" and return the suffix.
Example cell content: "FA-2604N3" → returns "2604N3".
"""
# Iterate over column B values
for idx, val in df.iloc[:, 1].items():
if isinstance(val, str) and "FA-" in val:
parts = val.split("FA-")
if len(parts) > 1:
suffix = parts[1].strip()
return suffix
raise ValueError('No cell containing "FA-" found in column B.')
def find_adjacent_value(df: pd.DataFrame, phrase: str) -> str:
"""Search the entire DataFrame for a cell containing *phrase* and return the value
from the cell immediately to its right (same row, next column)."""
for row_idx, row in df.iterrows():
for col_idx, cell in row.iteritems():
if isinstance(cell, str) and phrase in cell:
# Ensure there is a column to the right
if col_idx + 1 < df.shape[1]:
adjacent = df.iat[row_idx, col_idx + 1]
# Convert NaN to empty string if needed
if pd.isna(adjacent):
return ""
return str(adjacent)
else:
raise IndexError(f"Cell containing '{phrase}' is at the last column; no adjacent cell to copy.")
raise ValueError(f"Phrase '{phrase}' not found in the source sheet.")
def set_range(sheet: ezodf.Table, start_row: int, start_col: int, end_row: int, end_col: int, value: str) -> None:
"""Fill a rectangular range (inclusive) in the ODS sheet with *value*.
Rows and columns are zerobased indices.
"""
for r in range(start_row, end_row + 1):
for c in range(start_col, end_col + 1):
sheet[r, c].set_value(value)
def main() -> None:
# File names (relative to the script location / workspace root)
src_excel = "Production Order (mrp.production).xlsx"
template_ods = "A4004_v3.0-260617.ods"
# Load the Excel source file no header, treat everything as string
df = pd.read_excel(src_excel, header=None, dtype=str)
# 1. Serial number suffix (FA-...)
suffix = find_fa_suffix(df)
# 2. Component values copy the cell to the right of each label
barebone_val = find_adjacent_value(df, "All / Components / Barebone")
gpu_val = find_adjacent_value(df, "All / Components / GPU")
ram_val = find_adjacent_value(df, "All / Components / RAM")
cpu_val = find_adjacent_value(df, "All / Components / CPU")
ssd_val = find_adjacent_value(df, "All / Components / SSD")
raid_val = find_adjacent_value(df, "All / Components / RAID")
# 3. Determine output file name from cell A2 (row 1, column 0)
output_name_raw = df.iat[1, 0]
if pd.isna(output_name_raw) or not str(output_name_raw).strip():
output_name = "output"
else:
output_name = str(output_name_raw).strip()
output_file = f"{output_name}.ods"
# Load the ODS template
doc = ezodf.opendoc(template_ods)
# Assume the first sheet is the target adjust if needed
sheet = doc.sheets[0]
# 4. Populate the template ranges
# B1:C2 → rows 01, cols 12
set_range(sheet, 0, 1, 1, 2, suffix)
# C10:D10 → row 9, cols 23
set_range(sheet, 9, 2, 9, 3, barebone_val)
# C20:D23 → rows 1922, cols 23
set_range(sheet, 19, 2, 22, 3, gpu_val)
# C12:D19 → rows 1118, cols 23
set_range(sheet, 11, 2, 18, 3, ram_val)
# C11:D11 → row 10, cols 23
set_range(sheet, 10, 2, 10, 3, cpu_val)
# C24:D25 → rows 2324, cols 23
set_range(sheet, 23, 2, 24, 3, ssd_val)
# C27:D27 → row 26, cols 23
set_range(sheet, 26, 2, 26, 3, raid_val)
# 5. Save the populated template as a new file
doc.saveas(output_file)
print(f"Populated template saved as: {output_file}")