Files
limbach/folie8.py
T
marcus hinz 93bb19abf0 initial
2026-06-20 14:40:33 +02:00

139 lines
6.1 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
"""Folie 8 Funktionszuordnung je System (aus Anforderungskatalog_LIS_Fit-Gap v2.xlsx).
Pro System eine Kachel; Funktionen NUR dort = kraeftig/dunkel, auch woanders = grau mit
'· auch: ...'. Einspaltig, Fira Sans Condensed. (adesso-Stil, deutsch, dunkelblau.)"""
import os
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from openpyxl import load_workbook
from openpyxl.utils import column_index_from_string as ci
from adesso_style import (WHITE, INK, BLUE, TEAL, GREEN, CORAL, LIGHT, MUTE, RECF,
F, FC, chrome)
BG = RGBColor(0x0A, 0x3D, 0x6B)
SHARE = RGBColor(0x6B, 0x77, 0x85) # grau fuer "auch woanders"
# ---- Daten aus dem Excel lesen --------------------------------------------
HERE = os.path.dirname(os.path.abspath(__file__))
wb = load_workbook(os.path.join(HERE, "Anforderungskatalog_LIS_Fit-Gap v2.xlsx"), data_only=True)
ws = wb["Anforderungen & Fit-Gap"]
SYS = [('H', 'Order Entry'), ('N', 'AB+M'), ('O', 'Integrationsserver'), ('P', 'PVT'),
('Q', 'R. LabOps'), ('R', 'Sysmex'), ('S', 'SAP'), ('T', 'Consens')]
ABBR = {'Order Entry': 'OE', 'AB+M': 'AB+M', 'Integrationsserver': 'Int.-Server',
'PVT': 'PVT', 'R. LabOps': 'R.LabOps', 'Sysmex': 'Sysmex', 'SAP': 'SAP',
'Consens': 'Consens'}
reqs = []; cur = None
for r in range(5, ws.max_row + 1):
b = ws.cell(r, 2).value; c = ws.cell(r, 3).value
marks = {d: (ws.cell(r, ci(col)).value not in (None, '')) for col, d in SYS}
if b:
cur = {'name': (str(c).strip() if c else str(b)), 'm': dict(marks)}
reqs.append(cur)
elif cur:
for d, v in marks.items():
if v: cur['m'][d] = True
if c: cur['name'] = (cur['name'] + ' / ' + str(c).strip())
persys = {d: [] for _, d in SYS}
for req in reqs:
active = [d for _, d in SYS if req['m'][d]]
for d in active:
persys[d].append((req['name'], [o for o in active if o != d]))
for d in persys:
persys[d].sort(key=lambda it: (1 if it[1] else 0))
# ---- PPTX ------------------------------------------------------------------
prs = Presentation(); prs.slide_width = Inches(13.333); prs.slide_height = Inches(7.5)
SW, SH = prs.slide_width, prs.slide_height
s = prs.slides.add_slide(prs.slide_layouts[6])
def shp(kind, x, y, w, h, fill=None, line=None, lw=Pt(1), adj=None):
sh = s.shapes.add_shape(kind, Inches(x), Inches(y), Inches(w), Inches(h))
if fill is None: sh.fill.background()
else: sh.fill.solid(); sh.fill.fore_color.rgb = fill
if line is None: sh.line.fill.background()
else: sh.line.color.rgb = line; sh.line.width = lw
if adj is not None:
try: sh.adjustments[0] = adj
except Exception: pass
sh.shadow.inherit = False
return sh
def txt(x, y, w, h, t, size=12, color=WHITE, bold=False, align=PP_ALIGN.LEFT,
font=F, anchor=MSO_ANCHOR.MIDDLE):
tb = s.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)); tf = tb.text_frame
tf.word_wrap = True; tf.vertical_anchor = anchor
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
p = tf.paragraphs[0]; p.alignment = align
r = p.add_run(); r.text = t
r.font.size = Pt(size); r.font.bold = bold; r.font.name = font; r.font.color.rgb = color
return tb
def cut(t, n):
return t if len(t) <= n else t[:n].rstrip() + ""
def tile(x, y, w, h, title, items, accent, isize, sa, name_max):
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h, fill=WHITE, adj=0.05)
txt(x + 0.22, y + 0.14, w - 0.44, 0.32, title, size=14, color=INK, bold=True,
anchor=MSO_ANCHOR.MIDDLE)
n = len([i for i in items if not i[1]])
txt(x + w - 1.7, y + 0.18, 1.5, 0.24, "%d · %d nur hier" % (len(items), n),
size=8.5, color=SHARE, align=PP_ALIGN.RIGHT, font=FC, anchor=MSO_ANCHOR.MIDDLE)
shp(MSO_SHAPE.RECTANGLE, x + 0.22, y + 0.50, w - 0.44, 0.030, fill=accent)
tb = s.shapes.add_textbox(Inches(x + 0.22), Inches(y + 0.62), Inches(w - 0.40),
Inches(h - 0.74))
tf = tb.text_frame; tf.word_wrap = True; tf.vertical_anchor = MSO_ANCHOR.TOP
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
for i, (name, others) in enumerate(items):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = PP_ALIGN.LEFT; p.line_spacing = 0.96; p.space_after = Pt(sa)
r = p.add_run(); r.font.name = FC; r.font.size = Pt(isize)
if others:
r.text = cut(name, name_max); r.font.bold = False; r.font.color.rgb = SHARE
r2 = p.add_run(); r2.text = " · auch: " + ", ".join(ABBR[o] for o in others)
r2.font.name = FC; r2.font.size = Pt(isize - 1); r2.font.color.rgb = SHARE
else:
r.text = cut(name, name_max + 4); r.font.bold = True; r.font.color.rgb = INK
# ---- Hintergrund + Header --------------------------------------------------
shp(MSO_SHAPE.RECTANGLE, 0, 0, SW.inches, SH.inches, fill=BG)
chrome(s, "Funktionszuordnung je System", 9)
txt(0.42, 0.96, 12.5, 0.3,
"Dunkel/fett = nur dieses System · grau „· auch: …" + chr(34) + " = Funktion liegt auch in anderen Systemen",
size=11, color=LIGHT, anchor=MSO_ANCHOR.MIDDLE, font=FC)
CY, CH = 1.46, 5.42
COLS = [0.40, 3.58, 6.76, 9.94]; CW = 2.98
# Spalte 1: Integrationsserver (hoch)
tile(COLS[0], CY, CW, CH, "Integrationsserver", persys['Integrationsserver'],
CORAL, isize=9, sa=1.5, name_max=30)
# Spalte 2: Order Entry (hoch)
tile(COLS[1], CY, CW, CH, "Order Entry", persys['Order Entry'],
BLUE, isize=10.5, sa=5, name_max=30)
# Spalten 3 & 4: je 3 kleine Kacheln
SH3 = 1.68; GAP = 0.19
ys = [CY, CY + SH3 + GAP, CY + 2 * (SH3 + GAP)]
small3 = ['AB+M', 'Consens', 'R. LabOps']
small4 = ['PVT', 'Sysmex', 'SAP']
for name, y in zip(small3, ys):
tile(COLS[2], y, CW, SH3, name, persys[name], TEAL, isize=9.5, sa=3, name_max=30)
for name, y in zip(small4, ys):
tile(COLS[3], y, CW, SH3, name, persys[name], TEAL, isize=9.5, sa=3, name_max=30)
out = os.path.join(HERE, "Folie8.pptx")
prs.save(out)
print("saved", out)