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

193 lines
8.7 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 7 Integrationsserver / Event-Sourcing-Anbindung (DEUTSCH, adesso-Stil).
Eingaenge (Order Entry/CLAB, Probeneingang [Atras+PVT], Geraete, Middleware, MiBi/Hybase,
Stammdaten) -> Adapter-Ebene -> Event Store -> unten Event-Prozessoren, Projektionen,
Konsumenten (SinaBI, Archivierung). Hintergrund: solides dunkles Blau (BG)."""
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, MSO_CONNECTOR
from pptx.oxml.ns import qn
from adesso_style import (WHITE, INK, BLUE, TEAL, GREEN, CORAL, LIGHT, MUTE, RECF,
F, FC, chrome)
BG = RGBColor(0x0A, 0x3D, 0x6B)
GRAY = RGBColor(0xAE, 0xB7, 0xC2)
ADC = RGBColor(0xCF, 0xE2, 0xF7)
SUBC = RGBColor(0x3C, 0x4A, 0x5A) # zweite Zeile dunkel & gut lesbar
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=11, color=WHITE, bold=False, italic=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)
first = True
for line in t.split("\n"):
p = tf.paragraphs[0] if first else tf.add_paragraph(); first = False
p.alignment = align
r = p.add_run(); r.text = line
r.font.size = Pt(size); r.font.bold = bold; r.font.italic = italic
r.font.name = font; r.font.color.rgb = color
return tb
def conn(x1, y1, x2, y2, color=LIGHT, w=1.6, both=False):
c = s.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, Inches(x1), Inches(y1),
Inches(x2), Inches(y2))
c.line.color.rgb = color; c.line.width = Pt(w); c.shadow.inherit = False
ln = c.line._get_or_add_ln()
if both:
ln.append(ln.makeelement(qn('a:headEnd'), {'type': 'triangle'}))
ln.append(ln.makeelement(qn('a:tailEnd'), {'type': 'triangle'}))
return c
def group(x, y, w, h, title, tsize=11.5):
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h, fill=None, line=LIGHT, lw=Pt(1.25), adj=0.04)
txt(x, y + 0.05, w, 0.26, title, size=tsize, color=WHITE, bold=True,
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.TOP)
def box(x, y, w, h, title, sub=None, fill=WHITE, tcol=INK, tsize=10.5, line=None, lw=Pt(1)):
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h, fill=fill, line=line, lw=lw, adj=0.16)
tb = s.shapes.add_textbox(Inches(x + 0.05), Inches(y), Inches(w - 0.10), Inches(h))
tf = tb.text_frame; tf.word_wrap = True; tf.vertical_anchor = MSO_ANCHOR.MIDDLE
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
p = tf.paragraphs[0]; p.alignment = PP_ALIGN.CENTER; p.line_spacing = 0.98
r = p.add_run(); r.text = title; r.font.size = Pt(tsize); r.font.bold = True
r.font.name = F; r.font.color.rgb = tcol
if sub is not None:
p.space_after = Pt(2)
p2 = tf.add_paragraph(); p2.alignment = PP_ALIGN.CENTER; p2.line_spacing = 0.98
r2 = p2.add_run(); r2.text = sub; r2.font.size = Pt(tsize - 0.5)
r2.font.name = F; r2.font.color.rgb = SUBC
return tb
AD_Y, AD_H = 3.50, 0.48
def adapter(x, w, title):
box(x, AD_Y, w, AD_H, title, fill=ADC, tcol=INK, tsize=9, line=BLUE, lw=Pt(1.1))
# ---- Hintergrund + Header --------------------------------------------------
shp(MSO_SHAPE.RECTANGLE, 0, 0, SW.inches, SH.inches, fill=BG)
chrome(s, "Event Sourcing — Integrationsserver", 8)
# ---- Legende ---------------------------------------------------------------
ly = 0.95
def legsq(x, color, label, lw_txt):
shp(MSO_SHAPE.RECTANGLE, x, ly + 0.02, 0.15, 0.15, fill=color)
txt(x + 0.21, ly - 0.03, lw_txt, 0.26, label, size=10, color=WHITE, anchor=MSO_ANCHOR.MIDDLE)
legsq(0.40, CORAL, "Event Store", 1.2)
legsq(1.76, GREEN, "Prop-Limbach", 1.3)
legsq(3.28, ADC, "Adapter (own)", 1.4)
legsq(4.90, WHITE, "System", 0.9)
txt(6.30, 0.92, 6.63, 0.3,
"↕ publizieren & abonnieren ↓ publizieren grau = Kommunikation",
size=10, color=LIGHT, italic=True, anchor=MSO_ANCHOR.MIDDLE, align=PP_ALIGN.RIGHT)
# ---- EVENT STORE -----------------------------------------------------------
ST_X, ST_Y, ST_W, ST_H = 0.40, 4.18, 12.53, 0.60
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ST_X, ST_Y, ST_W, ST_H, fill=CORAL, line=INK, lw=Pt(3.5), adj=0.10)
txt(ST_X, ST_Y + 0.06, ST_W, 0.30, "Event Store — append-only Event-Log",
size=15, color=INK, bold=True, align=PP_ALIGN.CENTER)
txt(ST_X, ST_Y + 0.35, ST_W, 0.22, "kanonische Wahrheit · Replay-fähig · (Kafka)",
size=10.5, color=INK, align=PP_ALIGN.CENTER)
# ===========================================================================
# OBEN Systeme + Adapter-Ebene
# ===========================================================================
TGY, TGH = 1.28, 2.78
# --- 1: Order Entry ueber CLAB ---------------------------------------------
group(0.40, TGY, 2.70, TGH, "Order Entry über CLAB")
box(0.52, 1.62, 1.16, 0.42, "LabAccess")
box(1.82, 1.62, 1.16, 0.42, "MDN")
box(1.18, 2.22, 1.14, 0.44, "AB+M")
box(1.05, 2.84, 1.40, 0.42, "CLAB (LIS)", fill=GREEN)
adapter(0.78, 1.94, "CLAB-Adapter")
conn(1.10, 2.04, 1.55, 2.22); conn(2.40, 2.04, 1.95, 2.22)
conn(1.75, 2.66, 1.75, 2.84); conn(1.75, 3.26, 1.75, AD_Y)
conn(1.75, AD_Y + AD_H, 1.75, ST_Y, both=True)
# --- 2: Probeneingang (Atras SL + PVT) -------------------------------------
group(3.26, TGY, 1.95, TGH, "Probeneingang")
box(3.34, 2.30, 0.86, 0.52, "Atras SL")
box(4.27, 2.30, 0.86, 0.52, "PVT")
adapter(3.34, 1.79, "Adapter (Probe → Event)")
conn(2.32, 2.50, 3.34, 2.56, color=GRAY, both=True) # Praeanalytik-Kommunikation
txt(2.28, 2.04, 1.30, 0.34, "Präanalytik-\nKomm.", size=8, color=GRAY, italic=True,
align=PP_ALIGN.CENTER)
conn(3.77, 2.82, 3.95, AD_Y); conn(4.70, 2.82, 4.55, AD_Y)
conn(4.235, AD_Y + AD_H, 4.235, ST_Y)
# --- 3: Geraete -------------------------------------------------------------
group(5.37, TGY, 1.78, TGH, "Geräte-Adapter")
box(5.49, 2.10, 1.54, 0.70, "Geräte", "Sysmex · Analyzer")
adapter(5.45, 1.62, "Adapter (Device → Event)")
conn(6.26, 2.80, 6.26, AD_Y); conn(6.26, AD_Y + AD_H, 6.26, ST_Y, both=True)
# --- 4: Middleware ----------------------------------------------------------
group(7.31, TGY, 1.78, TGH, "Middleware")
box(7.43, 2.10, 1.54, 0.70, "Middleware-Systeme", "Myla/Maestria · LabOps · Liason")
adapter(7.39, 1.62, "Adapter (Middleware → Event)")
conn(8.20, 2.80, 8.20, AD_Y); conn(8.20, AD_Y + AD_H, 8.20, ST_Y, both=True)
# --- 5: MiBi (Hybase) -------------------------------------------------------
group(9.25, TGY, 1.70, TGH, "MiBi")
box(9.37, 2.10, 1.46, 0.70, "Hybase", "Resistenz / ID-Daten")
adapter(9.33, 1.54, "Adapter (MiBi → Event)")
conn(10.10, 2.80, 10.10, AD_Y); conn(10.10, AD_Y + AD_H, 10.10, ST_Y, both=True)
# --- 6: Stammdaten ----------------------------------------------------------
group(11.11, TGY, 1.82, TGH, "Stammdaten")
box(11.23, 2.10, 1.58, 0.70, "Stammdaten-Quellen", "SinaCRM · OTS/Znooni")
adapter(11.19, 1.66, "Adapter (MasterData → Event)")
conn(12.02, 2.80, 12.02, AD_Y); conn(12.02, AD_Y + AD_H, 12.02, ST_Y)
# ===========================================================================
# UNTEN Event-Prozessoren · Projektionen · Konsumenten
# ===========================================================================
BGY, BGH = 4.96, 1.96
group(0.40, BGY, 2.95, BGH, "Event-Prozessoren")
box(0.56, 5.42, 2.63, 0.55, "Mapping / Transformation")
box(0.56, 6.12, 2.63, 0.55, "Routing Engine")
conn(1.85, ST_Y + ST_H, 1.85, BGY, both=True)
group(3.50, BGY, 5.85, BGH, "Projektionen")
box(3.66, 5.46, 1.78, 1.02, "Auftragsstatus")
box(5.56, 5.46, 1.78, 1.02, "Audit Trail")
box(7.46, 5.46, 1.73, 1.02, "Reporting")
conn(6.40, ST_Y + ST_H, 6.40, BGY)
group(9.50, BGY, 3.43, BGH, "Konsumenten")
box(9.66, 5.38, 3.11, 0.68, "SinaBI (Power BI)", "Reporting / BI")
box(9.66, 6.12, 3.11, 0.68, "Archivierung · Vaultbox", "Roche Navify · LDT2")
conn(11.21, ST_Y + ST_H, 11.21, BGY)
out = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Folie7.pptx")
prs.save(out)
print("saved", out)