dotfiles/VSCodium/User/History/-2f7fe65f/Td2J.py

132 lines
4.8 KiB
Python
Raw Normal View History

2026-06-19 12:29:55 +00:00
#!/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}")