Updates
This commit is contained in:
BIN
BACKUP/Axio4_Nexio_Conduent Subsystem Cost Analysis.xlsx
Normal file
BIN
BACKUP/Axio4_Nexio_Conduent Subsystem Cost Analysis.xlsx
Normal file
Binary file not shown.
Binary file not shown.
38
octo_fill.py
38
octo_fill.py
@@ -46,7 +46,7 @@ COST_HEADER = "Unit Cost EUR @1000"
|
||||
SKIP_MPNS = {
|
||||
"", "0", "tbd", "n/a", "na", "-", "--", "---", "?", "none",
|
||||
"null", "nan", "xxx", "x", "dnf", "dnp", "do not fit",
|
||||
"do not populate",
|
||||
"do not populate", "total",
|
||||
}
|
||||
|
||||
logging.basicConfig(
|
||||
@@ -199,7 +199,10 @@ def _find_tables(indexed_rows: list[tuple[int, tuple]]):
|
||||
continue
|
||||
empty_streak = 0
|
||||
|
||||
if mfr.lower() == "manufacturer" and mpn.lower() == "mpn":
|
||||
# Detect a new table header anywhere in the row (handles sub-tables
|
||||
# at different column positions than the current table)
|
||||
dr_str_lower = [_cell(v).lower() for v in dr]
|
||||
if "manufacturer" in dr_str_lower and "mpn" in dr_str_lower:
|
||||
break
|
||||
|
||||
if mpn and mpn.lower() not in SKIP_MPNS:
|
||||
@@ -237,7 +240,10 @@ def fill_boms(
|
||||
for f in files:
|
||||
log.info(f"Processing {f.name}")
|
||||
try:
|
||||
wb = openpyxl.load_workbook(f)
|
||||
# data_only gives us resolved cell values (not formula strings) for
|
||||
# table/part detection; the writable wb is used for reading/writing prices.
|
||||
wb_ro = openpyxl.load_workbook(f, data_only=True, read_only=True)
|
||||
wb = openpyxl.load_workbook(f)
|
||||
except Exception as exc:
|
||||
log.error(f" Cannot open {f.name}: {exc}")
|
||||
continue
|
||||
@@ -246,14 +252,19 @@ def fill_boms(
|
||||
ws = wb[sheet_name]
|
||||
indexed = [
|
||||
(i, tuple(row))
|
||||
for i, row in enumerate(ws.iter_rows(values_only=True), start=1)
|
||||
for i, row in enumerate(wb_ro[sheet_name].iter_rows(values_only=True), start=1)
|
||||
]
|
||||
|
||||
for table in _find_tables(indexed):
|
||||
header_row = table["header_row"]
|
||||
data_rows = [r for r, _, _ in table["data"]]
|
||||
row_range = (
|
||||
f" (Excel rows {data_rows[0]}–{data_rows[-1]})"
|
||||
if data_rows else " (no data rows detected)"
|
||||
)
|
||||
log.info(
|
||||
f" Sheet '{sheet_name}' row {header_row}: "
|
||||
f"table at col {table['start_col']}, {len(table['data'])} parts"
|
||||
f"table at col {table['start_col']}, {len(table['data'])} parts{row_range}"
|
||||
)
|
||||
|
||||
# Find or create the cost column.
|
||||
@@ -272,8 +283,11 @@ def fill_boms(
|
||||
for c in range(table["start_col"], max_col + 1):
|
||||
val = ws.cell(header_row, c).value
|
||||
if val is not None:
|
||||
last_used = c
|
||||
if str(val).strip().lower() in KNOWN_COST_HEADERS:
|
||||
val_str = str(val).strip()
|
||||
# Don't count formula placeholders as "used" columns
|
||||
if not val_str.startswith("="):
|
||||
last_used = c
|
||||
if val_str.lower() in KNOWN_COST_HEADERS:
|
||||
cost_col = c
|
||||
break
|
||||
|
||||
@@ -288,7 +302,14 @@ def fill_boms(
|
||||
if isinstance(cell, MergedCell):
|
||||
continue
|
||||
existing = cell.value
|
||||
if existing is not None and str(existing).strip() not in ("", "0") and existing != 0:
|
||||
is_formula = isinstance(existing, str) and existing.startswith("=")
|
||||
is_empty = (
|
||||
existing is None
|
||||
or (isinstance(existing, str) and existing.strip() in ("", "0"))
|
||||
or (isinstance(existing, (int, float)) and existing == 0)
|
||||
)
|
||||
if not is_empty and not is_formula:
|
||||
log.info(f" Skip row {row_num} [{mpn}]: cell already has {repr(existing)}")
|
||||
total_skipped += 1
|
||||
continue
|
||||
|
||||
@@ -306,6 +327,7 @@ def fill_boms(
|
||||
total_missing += 1
|
||||
log.info(f" No match in Octopart: [{mfr}] [{mpn}]")
|
||||
|
||||
wb_ro.close()
|
||||
try:
|
||||
wb.save(f)
|
||||
log.info(f" Saved {f.name}")
|
||||
|
||||
Reference in New Issue
Block a user