diff --git a/Pflichtenheft_GruppeA.md b/Pflichtenheft_GruppeA.md index a078b6a..3c149a3 100644 --- a/Pflichtenheft_GruppeA.md +++ b/Pflichtenheft_GruppeA.md @@ -3,7 +3,7 @@ title: "Pflichtenheft" subtitle: "Desktop-Fakturierungsanwendung — Gruppe A: Prozess / Dokumentenzyklus" author: - Team 1 – Gruppe A -version: "1.0" +version: "1.1" lang: de-DE toc: true toc-depth: 3 @@ -22,7 +22,7 @@ header-includes: | \fancyhf{} \fancyhead[L]{Team 1 – Gruppe A} \fancyhead[C]{Pflichtenheft} - \fancyhead[R]{Version 1.0} + \fancyhead[R]{Version 1.1} \fancyfoot[C]{\thepage\ /\ \pageref{LastPage}} \renewcommand{\headrulewidth}{0.4pt} \renewcommand{\footrulewidth}{0pt} @@ -50,6 +50,7 @@ und den Modultest der Komponente *Prozess / Dokumentenzyklus*. | Version | Datum | Autor | Grund der Änderung | |---------|------------|-----------------------------|---------------------| | 1.0 | 09.06.2026 | Lucas Strubel, Luca Kaiser | Initiale Erstellung | +| 1.1 | 13.06.2026 | Lucas Strubel, Luca Kaiser | Einfügen der UML-Diagramme (Klassen- und Sequenzdiagramm) | \newpage @@ -391,32 +392,33 @@ public interface BelegnummernGenerator { ## 7. Systemarchitektur (logisch, grob) Die Komponente folgt einer einfachen Schichtung: die GUI (Gruppe D) ruft den -`DokumentService` auf, der die Fachlogik kapselt und die Dienste `BelegnummernGenerator`, -`KundenService`, `ProduktService` und `PdfExporter` nutzt. Belege werden über ein -`DokumentRepository` im lokalen Dateisystem persistiert. +`DokumentService` (realisiert durch `StandardDokumentService`) auf, der die Fachlogik +kapselt und die Dienste `BelegnummernGenerator`, `KundenService`, `ProduktService` und +`PdfExporter` nutzt. Belege werden über ein `DokumentRepository` im lokalen Dateisystem +persistiert (realisiert als JSON-Ablage). Nach jeder schreibenden Operation meldet der +`DokumentService` die Datenänderung über einen **`EreignisBus`** (Observer-Muster, Paket +`gemeinsam`; `melde(DatenBereich.DOKUMENTE)`); die Modulansichten der Gruppe D abonnieren +diesen Bus und aktualisieren sich automatisch. ### 7.1 Klassendiagramm - - -![Abbildung 1: UML-Klassendiagramm Dokumentenzyklus (Gruppe A)] +![Abbildung 1: UML-Klassendiagramm Dokumentenzyklus (Gruppe A)](diagramme/klassendiagramm_dokumentenzyklus.png) **Beschreibung zu Abbildung 1:** Das Klassendiagramm zeigt die abstrakte Oberklasse `Dokument` mit den Spezialisierungen `Angebot`, `Auftragsbestaetigung`, `Lieferschein` und `Rechnung` (Vererbung). Ein `Dokument` besteht aus einer bis vielen `Dokumentposition`- -Objekten (Komposition `Dokument` ◆—— `Dokumentposition`, Multiplizität `1..*`). Jede +Objekten (Komposition zwischen `Dokument` und `Dokumentposition`, Multiplizität `1..*`). Jede `Dokumentposition` referenziert ein `Produkt` (Gruppe B), ein `Dokument` referenziert einen `Kunde` (Gruppe C) — jeweils über die Stammdatennummer (lose Kopplung). Der `DokumentService` orchestriert die Erstellung und nutzt den `BelegnummernGenerator` (Vergabe lückenloser -Belegnummern), die Schnittstellen `KundenService`/`ProduktService` (Stammdaten) sowie den -`PdfExporter` (PDF-Export). Der Status eines Belegs wird über das Enum `DokumentStatus` -abgebildet. +Belegnummern), die Schnittstellen `KundenService`/`ProduktService` (Stammdaten), den +`PdfExporter` (PDF-Export) sowie den `EreignisBus` (Benachrichtigung der Modulansichten +nach Datenänderungen, Observer-Muster). Der Status eines Belegs wird über das Enum +`DokumentStatus` abgebildet. ### 7.2 Sequenzdiagramm - - -![Abbildung 2: UML-Sequenzdiagramm „Rechnung erstellen" (Gruppe A)] +![Abbildung 2: UML-Sequenzdiagramm „Rechnung erstellen" (Gruppe A)](diagramme/sequenz_rechnung_erstellen.png) **Beschreibung zu Abbildung 2:** Das Sequenzdiagramm stellt den Ablauf *Rechnung erstellen* dar. Die Anwender:in löst über die GUI (Gruppe D) `erstelleRechnung(kundenNr, positionen)` @@ -425,8 +427,11 @@ am `DokumentService` aus. Dieser ermittelt über `KundenService.findeKunde(...)` Summe Netto-, Steuer- und Bruttobetrag (F-23), fordert vom `BelegnummernGenerator` mit `naechsteNummer(RECHNUNG, jahr)` eine lückenlose Rechnungsnummer an (GR-01), setzt das Standard-Zahlungsziel (+14 Tage, GR-06), persistiert den Beleg über das `DokumentRepository` -und exportiert ihn über `PdfExporter.exportiere(...)`. Abschließend wird die gespeicherte -`Rechnung` an die GUI zurückgegeben. +und meldet die Änderung über `EreignisBus.melde(DOKUMENTE)` an die abonnierten Modulansichten. +Abschließend wird die gespeicherte `Rechnung` an die GUI zurückgegeben. Der PDF-Export ist ein +**separater** Vorgang (im Diagramm unten dargestellt): über `exportierePdf(...)` lädt der +`DokumentService` den Beleg erneut aus dem `DokumentRepository` und exportiert ihn mittels +`PdfExporter.exportiere(...)` in das lokale Dateisystem (F-15, IF-01). --- @@ -516,21 +521,57 @@ Die folgenden Testfälle sind deterministisch (feste Ein-/Ausgaben) und mit JUni umsetzbar. Geldbeträge werden als `BigDecimal` mit Scale 2 erwartet (`assertEquals(new BigDecimal("119.00"), …)` bzw. `compareTo`). -| TC | Abgedeckte PH-Anf. | Vorbedingung | Eingabe | Erwartetes Ergebnis | -|-------|--------------------|--------------|---------|---------------------| -| TC-01 | F-23, F-03 | Position mit Netto 100.00 €, Steuersatz 0.19 | `berechne()` | Steuer = 19.00, Brutto = 119.00 (Scale 2) | -| TC-02 | F-23 | Einzelpreis 50.00 €, Menge 3 | Positionssumme berechnen | positionssummeNetto = 150.00 | -| TC-03 | F-03, F-13 | Beleg mit 2 Positionen (150.00 € @ 0.19; 50.00 € @ 0.07) | Summen berechnen | summeNetto = 200.00, summeSteuer = 32.00, summeBrutto = 232.00 | -| TC-04 | F-12, GR-01 | Letzte Rechnungsnummer `R-2026-000123` | `naechsteNummer(RECHNUNG, 2026)` | liefert `R-2026-000124` (lückenlos) | -| TC-05 | F-12 (Format) | Zähler = 7, Jahr 2026 | `naechsteNummer(RECHNUNG, 2026)` | liefert `R-2026-000007` (führende Nullen, `String`) | -| TC-06 | F-14, GR-06 | Rechnungsdatum 2026-06-09, kein Zahlungsziel | Rechnung erstellen | zahlungsziel = 2026-06-23 (+14 Tage) | -| TC-07 | F-14 | Rechnungsdatum 2026-06-09, Zahlungsziel 2026-07-31 | Rechnung erstellen | zahlungsziel = 2026-07-31 (übernommen) | -| TC-08 | F-24, NF-INT-01 | Rechnung im Status `VERSENDET` | `setzePosition(...)` / Änderung | wirft `IllegalStateException` | -| TC-09 | F-19, F-20 | Rechnung im Status `OFFEN` | `storniere()` | Status = `STORNIERT`; nicht in `offeneRechnungen()`; `storniertAm` gesetzt | -| TC-10 | F-22, GR-05 | Angebot `AN-2026-000001` mit Kunde + 2 Positionen | `ausAngebot(angebot)` (AB erzeugen) | AB übernimmt Kunde/Positionen/Mengen; `vorgaengerNr = "AN-2026-000001"` | -| TC-11 | F-23, F-24 | Rechnung mit Produkt @ 50.00 €; danach Produktpreis → 80.00 € | erste Rechnung erneut lesen | einzelpreisNetto bleibt 50.00 (Snapshot unverändert) | -| TC-12 | F-18, NF-USE-02 | Rechnung ohne Kunde **oder** ohne Position | `speichere()` | Speichern abgelehnt; Validierungsfehler benennt fehlendes Pflichtfeld | -| TC-13 | F-11, F-12, F-13 | Kunde + 1 Position vorhanden | vollständige Rechnung erstellen | Rechnung gespeichert, Nummer vergeben, alle § 14 UStG-Pflichtangaben gesetzt | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC | Abgedeckte PH-Anf. | Vorbedingung | Eingabe | Erwartetes Ergebnis | ++=======+====================+=============================+===========================+=============================+ +| TC-01 | F-23, F-03 | Position mit Netto 100.00 | `berechne()` | Steuer = 19.00, Brutto = | +| | | €, Steuersatz 0.19 | | 119.00 (Scale 2) | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-02 | F-23 | Einzelpreis 50.00 €, | Positionssumme | positionssummeNetto = | +| | | Menge 3 | berechnen | 150.00 | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-03 | F-03, F-13 | Beleg mit 2 Positionen | Summen berechnen | summeNetto = 200.00, | +| | | (150.00 € @ 0.19; | | summeSteuer = 32.00, | +| | | 50.00 € @ 0.07) | | summeBrutto = 232.00 | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-04 | F-12, GR-01 | Letzte Rechnungsnummer | `naechsteNummer` | liefert `R-2026-000124` | +| | | `R-2026-000123` | `(RECHNUNG, 2026)` | (lückenlos) | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-05 | F-12 (Format) | Zähler = 7, Jahr 2026 | `naechsteNummer` | liefert `R-2026-000007` | +| | | | `(RECHNUNG, 2026)` | (führende Nullen, `String`) | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-06 | F-14, GR-06 | Rechnungsdatum 2026-06-09, | Rechnung erstellen | zahlungsziel = | +| | | kein Zahlungsziel | | 2026-06-23 (+14 Tage) | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-07 | F-14 | Rechnungsdatum 2026-06-09, | Rechnung erstellen | zahlungsziel = 2026-07-31 | +| | | Zahlungsziel 2026-07-31 | | (übernommen) | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-08 | F-24, NF-INT-01 | Rechnung im Status | `setzePosition(...)` / | wirft | +| | | `VERSENDET` | Änderung | `IllegalStateException` | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-09 | F-19, F-20 | Rechnung im Status `OFFEN` | `storniere()` | Status = `STORNIERT`; | +| | | | | nicht in | +| | | | | `offeneRechnungen()`; | +| | | | | `storniertAm` gesetzt | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-10 | F-22, GR-05 | Angebot `AN-2026-000001` | `ausAngebot(angebot)` | AB übernimmt Kunde/ | +| | | mit Kunde + 2 Positionen | (AB erzeugen) | Positionen/Mengen; | +| | | | | `vorgaengerNr` = | +| | | | | `"AN-2026-000001"` | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-11 | F-23, F-24 | Rechnung mit Produkt @ | erste Rechnung erneut | einzelpreisNetto bleibt | +| | | 50.00 €; danach | lesen | 50.00 (Snapshot | +| | | Produktpreis → 80.00 € | | unverändert) | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-12 | F-18, NF-USE-02 | Rechnung ohne Kunde | `speichere()` | Speichern abgelehnt; | +| | | **oder** ohne Position | | Validierungsfehler benennt | +| | | | | fehlendes Pflichtfeld | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ +| TC-13 | F-11, F-12, F-13 | Kunde + 1 Position | vollständige Rechnung | Rechnung gespeichert, | +| | | vorhanden | erstellen | Nummer vergeben, alle | +| | | | | § 14 UStG-Pflichtangaben | +| | | | | gesetzt | ++-------+--------------------+-----------------------------+---------------------------+-----------------------------+ Damit sind 13 Testfälle (> 10) spezifiziert, die alle funktionalen Kernregeln (F-12, F-14, F-18, F-22, F-23, F-24) sowie die zentralen Geschäftsregeln (GR-01, GR-02, GR-03, GR-05, diff --git a/Pflichtenheft_GruppeA.pdf b/Pflichtenheft_GruppeA.pdf index b91933b..4ebd020 100644 Binary files a/Pflichtenheft_GruppeA.pdf and b/Pflichtenheft_GruppeA.pdf differ diff --git a/Pflichtenheft_GruppeB.md b/Pflichtenheft_GruppeB.md index beeed17..3614a44 100644 --- a/Pflichtenheft_GruppeB.md +++ b/Pflichtenheft_GruppeB.md @@ -347,7 +347,11 @@ Die Komponente folgt einer einfachen Schichtung: die GUI (Gruppe D) ruft den Löschsperre) kapselt und die Dienste `ProduktnummernGenerator`, `ProduktRepository` und `ProduktReferenzPruefung` (Gruppe A) nutzt. Gegenüber Gruppe A implementiert die Komponente das Interface `ProduktService`. Produkte werden über das `ProduktRepository` -im lokalen Dateisystem persistiert. +im lokalen Dateisystem persistiert (realisiert als JSON-Ablage). Nach jeder schreibenden +Operation (Anlegen, Ändern, Löschen) meldet der `ProduktVerwaltungsService` die Änderung +über einen **`EreignisBus`** (Observer-Muster, Paket `gemeinsam`; +`melde(DatenBereich.PRODUKTE)`), den die Produktansicht der Gruppe D abonniert und sich +daraufhin automatisch aktualisiert. ### 7.1 Klassendiagramm @@ -361,8 +365,10 @@ mit ihren Attributen (Kapitel 6.1). Der `ProduktVerwaltungsService` orchestriert Produktnummern, F-02), das `ProduktRepository` (Persistenz, IF-01) und die von Gruppe A bereitgestellte Schnittstelle `ProduktReferenzPruefung` (Löschsperre, F-09/F-10). Zusätzlich realisiert der `ProduktVerwaltungsService` das Interface `ProduktService` -(lesender Zugriff für Gruppe A, F-14). Dokumentpositionen (Gruppe A) referenzieren ein -`Produkt` ausschließlich über die Produktnummer (lose Kopplung). +(lesender Zugriff für Gruppe A, F-14) und meldet Datenänderungen über den `EreignisBus` +(Observer-Muster) an die abonnierte Produktansicht der Gruppe D. Dokumentpositionen +(Gruppe A) referenzieren ein `Produkt` ausschließlich über die Produktnummer (lose +Kopplung). ### 7.2 Sequenzdiagramm diff --git a/Pflichtenheft_GruppeC.md b/Pflichtenheft_GruppeC.md index b7548c7..d6c8931 100644 --- a/Pflichtenheft_GruppeC.md +++ b/Pflichtenheft_GruppeC.md @@ -349,7 +349,11 @@ Die Komponente folgt einer einfachen Schichtung: die GUI (Gruppe D) ruft den Löschsperre GR-04) kapselt und die Dienste `KundennummernGenerator`, `KundenRepository` und `KundenReferenzPruefung` (Gruppe A) nutzt. Gegenüber Gruppe A implementiert die Komponente das Interface `KundenService`. Kunden werden über das `KundenRepository` im -lokalen Dateisystem persistiert. +lokalen Dateisystem persistiert (realisiert als JSON-Ablage). Nach jeder schreibenden +Operation (Anlegen, Ändern, Löschen) meldet der `KundenVerwaltungsService` die Änderung +über einen **`EreignisBus`** (Observer-Muster, Paket `gemeinsam`; +`melde(DatenBereich.KUNDEN)`), den die Kundenansicht der Gruppe D abonniert und sich +daraufhin automatisch aktualisiert. ### 7.1 Klassendiagramm @@ -363,8 +367,9 @@ mit ihren Attributen (Kapitel 6.1). Der `KundenVerwaltungsService` orchestriert Kundennummern, F-02), das `KundenRepository` (Persistenz, IF-01) und die von Gruppe A bereitgestellte Schnittstelle `KundenReferenzPruefung` (Löschsperre GR-04, F-09/F-10). Zusätzlich realisiert der `KundenVerwaltungsService` das Interface `KundenService` -(lesender Zugriff für Gruppe A, F-14). Dokumente (Gruppe A) referenzieren einen `Kunde` -ausschließlich über die Kundennummer (lose Kopplung). +(lesender Zugriff für Gruppe A, F-14) und meldet Datenänderungen über den `EreignisBus` +(Observer-Muster) an die abonnierte Kundenansicht der Gruppe D. Dokumente (Gruppe A) +referenzieren einen `Kunde` ausschließlich über die Kundennummer (lose Kopplung). ### 7.2 Sequenzdiagramm diff --git a/Pflichtenheft_GruppeD.md b/Pflichtenheft_GruppeD.md index a01e70f..d156149 100644 --- a/Pflichtenheft_GruppeD.md +++ b/Pflichtenheft_GruppeD.md @@ -365,13 +365,17 @@ public interface ProduktService { ## 7. Systemarchitektur (logisch, grob) -Die Komponente folgt dem Muster *Model–View–Controller*: Die Views (Hauptfenster, -Modulansichten, Wizard-Dialog) enthalten ausschließlich Darstellung; die Controller -(`HauptController`, `StammdatenController`, `RechnungsWizardController`, -`DokumentListenController`) kapseln Dialogführung und Vollständigkeitsprüfungen und rufen -die Service-Schnittstellen der Gruppen A–C auf. Das UI-Zustandsmodell -(`RechnungsWizardModel`, `Meldung`) ist frei von GUI-Framework-Klassen und damit im -Modultest ohne Oberfläche prüfbar. +Die Komponente folgt dem Muster *Model–View–Controller*: Die Views (das Hauptfenster +`HauptFenster`, die Modulansichten `KundenPanel`/`ProduktPanel`/`DokumentListenPanel`, der +Wizard-Dialog) enthalten die Darstellung; die Controller (`StammdatenController`, +`RechnungsWizardController`, `DokumentListenController`) kapseln Dialogführung und +Vollständigkeitsprüfungen und rufen die Service-Schnittstellen der Gruppen A–C auf. Das +`HauptFenster` (ein `JFrame`) hält die Navigationsleiste und schaltet die Modulansichten +über ein `CardLayout` um; die Verdrahtung von Panels, Controllern und Services erfolgt beim +Programmstart (`Main`). Die Modulansichten abonnieren den gemeinsamen `EreignisBus` +(Observer-Muster, Paket `gemeinsam`) und aktualisieren sich nach Datenänderungen der +Gruppen A–C automatisch. Das UI-Zustandsmodell (`RechnungsWizardModel`, `Meldung`) ist frei +von GUI-Framework-Klassen und damit im Modultest ohne Oberfläche prüfbar. ### 7.1 Klassendiagramm @@ -379,16 +383,18 @@ Modultest ohne Oberfläche prüfbar. ![Abbildung 1: UML-Klassendiagramm Programmoberfläche (Gruppe D)] -**Beschreibung zu Abbildung 1:** Das Klassendiagramm zeigt die Controller-Schicht der -Oberfläche. Der `HauptController` verwaltet die Navigation (F-01, F-02) und erzeugt die -Modul-Controller. Der `StammdatenController` bedient Listen-, Such- und Formularansichten -für Kunden und Produkte und nutzt dazu `KundenService` (Gruppe C) und `ProduktService` -(Gruppe B). Der `RechnungsWizardController` führt die Schrittfolge des Enums -`WizardSchritt` über das `RechnungsWizardModel` (Komposition) und delegiert das Speichern -an den `DokumentService` (Gruppe A). Der `DokumentListenController` stellt die -Dokumentliste mit Statusfilter dar und bietet die Belegaktionen an (F-06–F-08, F-14, -F-15). Fehler- und Erfolgsmeldungen werden einheitlich über die Klasse `Meldung` -dargestellt (F-16, F-17). +**Beschreibung zu Abbildung 1:** Das Klassendiagramm zeigt die View- und Controller-Schicht +der Oberfläche. Das `HauptFenster` (ein `JFrame`) verwaltet die Navigation (F-01, F-02): es +nimmt die drei Modulansichten (`KundenPanel`, `ProduktPanel`, `DokumentListenPanel`) +entgegen und schaltet sie über ein `CardLayout` um. Der `StammdatenController` bedient +Listen-, Such- und Formularansichten für Kunden und Produkte und nutzt dazu `KundenService` +(Gruppe C) und `ProduktService` (Gruppe B). Der `RechnungsWizardController` führt die +Schrittfolge des Enums `WizardSchritt` über das `RechnungsWizardModel` (Komposition) und +delegiert das Speichern an den `DokumentService` (Gruppe A). Der `DokumentListenController` +stellt die Dokumentliste mit Statusfilter dar und bietet die Belegaktionen an (F-06–F-08, +F-14, F-15). Die Modulansichten abonnieren den gemeinsamen `EreignisBus` (Observer-Muster) +und aktualisieren sich nach Datenänderungen selbsttätig. Fehler- und Erfolgsmeldungen werden +einheitlich über die Klasse `Meldung` dargestellt (F-16, F-17). ### 7.2 Sequenzdiagramm diff --git a/diagramme/klassendiagramm_dokumentenzyklus.png b/diagramme/klassendiagramm_dokumentenzyklus.png new file mode 100644 index 0000000..359d4b5 Binary files /dev/null and b/diagramme/klassendiagramm_dokumentenzyklus.png differ diff --git a/diagramme/klassendiagramm_dokumentenzyklus.puml b/diagramme/klassendiagramm_dokumentenzyklus.puml new file mode 100644 index 0000000..84a3731 --- /dev/null +++ b/diagramme/klassendiagramm_dokumentenzyklus.puml @@ -0,0 +1,173 @@ +@startuml klassendiagramm_dokumentenzyklus +' UML-Klassendiagramm Dokumentenzyklus (Pflichtenheft Gruppe A, Abschnitt 7.1) +' Layout-Engine Smetana -> kein Graphviz erforderlich. +!pragma layout smetana + +skinparam shadowing false +skinparam classAttributeIconSize 0 +skinparam linetype ortho +hide empty members + +title UML-Klassendiagramm — Dokumentenzyklus (Gruppe A) + +' ===================== Domänenmodell ===================== + +abstract class Dokument { + - belegnummer : String + - datum : LocalDate + - kundenReferenz : String + - kundeName : String + - kundeAnschrift : String + - status : DokumentStatus + - vorgaengerNr : String + - summeNetto : BigDecimal + - summeSteuer : BigDecimal + - summeBrutto : BigDecimal + + {abstract} belegtyp() : Belegtyp + + setzePositionen(positionen : List) + + berechneSummen() + + versende() + + pruefeAenderbar() +} + +class Angebot { + - gueltigBis : LocalDate +} + +class Auftragsbestaetigung { +} + +class Lieferschein { + - lieferdatum : LocalDate +} + +class Rechnung { + - leistungsdatum : LocalDate + - zahlungsziel : LocalDate + - storniertAm : LocalDate + - storniertVon : String + + storniere(datum : LocalDate, benutzer : String) +} + +class Dokumentposition { + - produktReferenz : String + - bezeichnung : String + - menge : int + - einzelpreisNetto : BigDecimal + - steuersatz : BigDecimal + - positionssummeNetto : BigDecimal + + getSteuerbetrag() : BigDecimal + + getPositionssummeBrutto() : BigDecimal +} + +enum DokumentStatus { + ENTWURF + OFFEN + VERSENDET + STORNIERT +} + +enum Belegtyp { + ANGEBOT + AUFTRAGSBESTAETIGUNG + LIEFERSCHEIN + RECHNUNG +} + +' Vererbung der vier Belegtypen +Dokument <|-- Angebot +Dokument <|-- Auftragsbestaetigung +Dokument <|-- Lieferschein +Dokument <|-- Rechnung + +' Komposition: ein Dokument besteht aus 1..* Positionen +Dokument "1" *-- "1..*" Dokumentposition : positionen + +Dokument --> DokumentStatus : status +Dokument ..> Belegtyp : belegtyp() + +' ===================== Service-Schicht ===================== + +interface DokumentService <> { + + erstelleAngebot(...) : Angebot + + erstelleAuftragsbestaetigung(...) : Auftragsbestaetigung + + erstelleLieferschein(...) : Lieferschein + + erstelleRechnung(...) : Rechnung + + erzeugeFolgebeleg(belegnummer : String) : Dokument + + storniere(rechnungsnummer : String) + + berechneSummen(...) : Summen + + exportierePdf(belegnummer : String, zielDatei : Path) +} + +class StandardDokumentService { +} + +interface BelegnummernGenerator <> { + + naechsteNummer(typ : Belegtyp, jahr : int) : String +} + +interface DokumentRepository <> { + + speichere(dokument : Dokument) : Dokument + + findeNachNummer(belegnummer : String) : Dokument + + alle() : List +} + +interface PdfExporter <> { + + exportiere(dokument : Dokument, zielDatei : Path) +} + +class EreignisBus { + + abonniere(bereich : DatenBereich, beobachter : Runnable) + + melde(bereich : DatenBereich) +} + +enum DatenBereich { + KUNDEN + PRODUKTE + DOKUMENTE +} + +' DTOs (Eingabe/Ausgabe des Service) +class Positionsangabe <> { + + produktnummer : String + + menge : int +} + +class Summen <> { + + netto : BigDecimal + + steuer : BigDecimal + + brutto : BigDecimal +} + +DokumentService <|.. StandardDokumentService + +StandardDokumentService ..> BelegnummernGenerator +StandardDokumentService ..> DokumentRepository +StandardDokumentService ..> PdfExporter +StandardDokumentService ..> EreignisBus +StandardDokumentService ..> Dokument : erzeugt +EreignisBus ..> DatenBereich +DokumentService ..> Positionsangabe +DokumentService ..> Summen + +' ===================== Externe Komponenten (lose Kopplung) ===================== + +interface KundenService <> { + + findeKunde(kundennummer : String) : Kunde +} + +interface ProduktService <> { + + findeProdukt(produktnummer : String) : Produkt +} + +class Kunde <> +class Produkt <> + +StandardDokumentService ..> KundenService +StandardDokumentService ..> ProduktService + +' Referenz nur über die Stammdatennummer (lose Kopplung) +Dokument ..> Kunde : "über Kundennummer" +Dokumentposition ..> Produkt : "über Produktnummer" + +@enduml diff --git a/diagramme/sequenz_rechnung_erstellen.png b/diagramme/sequenz_rechnung_erstellen.png new file mode 100644 index 0000000..8e9a88a Binary files /dev/null and b/diagramme/sequenz_rechnung_erstellen.png differ diff --git a/diagramme/sequenz_rechnung_erstellen.puml b/diagramme/sequenz_rechnung_erstellen.puml new file mode 100644 index 0000000..a61a6ff --- /dev/null +++ b/diagramme/sequenz_rechnung_erstellen.puml @@ -0,0 +1,81 @@ +@startuml sequenz_rechnung_erstellen +' UML-Sequenzdiagramm "Rechnung erstellen" (Pflichtenheft Gruppe A, Abschnitt 7.2) +' Ablauf gemäß StandardDokumentService.erstelleRechnung(...) und exportierePdf(...). + +skinparam shadowing false +skinparam sequenceMessageAlign center +hide footbox + +title UML-Sequenzdiagramm — „Rechnung erstellen" (Gruppe A) + +participant "GUI\n(Gruppe D)" as GUI +participant "dokumentService :\nStandardDokumentService" as DS +participant "kundenService :\nKundenService" as KS +participant "produktService :\nProduktService" as PS +participant "nummernGenerator :\nBelegnummernGenerator" as NG +participant "repository :\nDokumentRepository" as REPO +participant "ereignisBus :\nEreignisBus" as EB + +GUI -> DS : erstelleRechnung(kundenNr, positionen,\nrechnungsdatum, zahlungsziel) +activate DS + +DS -> KS : findeKunde(kundenNr) +activate KS +KS --> DS : kunde +deactivate KS + +loop für jede Positionsangabe + DS -> PS : findeProdukt(produktnummer) + activate PS + PS --> DS : produkt + deactivate PS + DS -> DS : new Dokumentposition(...) + note right of DS : Preis- und Steuersatz-Snapshot\ndes Produkts (GR-03, F-23) +end + +DS -> NG : naechsteNummer(RECHNUNG, jahr) +activate NG +NG --> DS : "R-2026-000124" +deactivate NG + +DS -> DS : zahlungsziel = rechnungsdatum + 14 Tage\n(falls nicht angegeben, GR-06) + +create participant "rechnung :\nRechnung" as R +DS -> R : «create» +DS -> R : setzePositionen(positionen) +activate R +R -> R : berechneSummen() +deactivate R +DS -> R : setzeStatus(OFFEN) + +DS -> REPO : speichere(rechnung) +activate REPO +REPO --> DS : rechnung +deactivate REPO + +DS -> EB : melde(DOKUMENTE) +activate EB +note right of EB : benachrichtigt die abonnierten\nModulansichten (Observer-Muster) +EB --> DS +deactivate EB + +DS --> GUI : rechnung +deactivate DS + +group Separater Aufruf: PDF-Export (F-15, IF-01) + participant "pdfExporter :\nPdfExporter" as PDF + GUI -> DS : exportierePdf(belegnummer, zielDatei) + activate DS + DS -> REPO : findeNachNummer(belegnummer) + activate REPO + REPO --> DS : rechnung + deactivate REPO + DS -> PDF : exportiere(rechnung, zielDatei) + activate PDF + PDF --> DS + deactivate PDF + DS --> GUI : PDF im lokalen Dateisystem + deactivate DS +end + +@enduml diff --git a/tools/plantuml.jar b/tools/plantuml.jar new file mode 100644 index 0000000..bdecddf Binary files /dev/null and b/tools/plantuml.jar differ