fix: GUI-Kompatibilität DokumentenService Fassade + DokumentPanel gefixt
parent
9f22667592
commit
92dbd53986
|
|
@ -99,3 +99,33 @@ public abstract class Dokument {
|
||||||
getClass().getSimpleName(), dokumentNummer, kundenId, datum, status);
|
getClass().getSimpleName(), dokumentNummer, kundenId, datum, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Alias-Methoden für GUI-Kompatibilität ===
|
||||||
|
|
||||||
|
/** Alias für getDokumentNummer() – GUI-Kompatibilität. */
|
||||||
|
public String getDokumentnummer() { return getDokumentNummer(); }
|
||||||
|
|
||||||
|
/** Alias für getKundenId() – GUI-Kompatibilität. */
|
||||||
|
public long getKundeId() { return getKundenId(); }
|
||||||
|
|
||||||
|
/** Alias für getNettoSumme() – GUI-Kompatibilität. */
|
||||||
|
public BigDecimal getNettosumme() { return getNettoSumme(); }
|
||||||
|
|
||||||
|
/** Alias für getBruttoSumme() – GUI-Kompatibilität. */
|
||||||
|
public BigDecimal getBruttosumme() { return getBruttoSumme(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt an ob dieses Dokument festgeschrieben ist.
|
||||||
|
* Standard: false. Wird in Rechnung auf true gesetzt (PHGUI11).
|
||||||
|
*/
|
||||||
|
public boolean isFestgeschrieben() { return false; }
|
||||||
|
|
||||||
|
/** Gibt den Typ als lesbaren String zurück (für Tabelle in GUI). */
|
||||||
|
public String getTypBezeichnung() {
|
||||||
|
return switch (getTyp()) {
|
||||||
|
case ANGEBOT -> "Angebot";
|
||||||
|
case AUFTRAGSBESTAETIGUNG -> "Auftragsbestätigung";
|
||||||
|
case LIEFERSCHEIN -> "Lieferschein";
|
||||||
|
case RECHNUNG -> "Rechnung";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,3 +72,22 @@ public class DokumentPosition {
|
||||||
produktId, bezeichnungSnapshot, menge, einzelpreisNettoSnapshot, mwstSatzSnapshot);
|
produktId, bezeichnungSnapshot, menge, einzelpreisNettoSnapshot, mwstSatzSnapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Alias-Methoden für GUI-Kompatibilität ===
|
||||||
|
|
||||||
|
/** Alias für getBezeichnungSnapshot() – GUI-Kompatibilität. */
|
||||||
|
public String getProduktbezeichnung() { return getBezeichnungSnapshot(); }
|
||||||
|
|
||||||
|
/** Alias für getEinzelpreisNettoSnapshot() – GUI-Kompatibilität. */
|
||||||
|
public BigDecimal getEinzelpreisNetto() { return getEinzelpreisNettoSnapshot(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MwSt-Satz in Prozent (z. B. 19.00 statt 0.19) – GUI-Kompatibilität.
|
||||||
|
*/
|
||||||
|
public BigDecimal getMehrwertsteuerSatz() {
|
||||||
|
return getMwstSatzSnapshot().multiply(java.math.BigDecimal.valueOf(100))
|
||||||
|
.setScale(0, java.math.RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Alias für getNettoGesamt() – GUI-Kompatibilität. */
|
||||||
|
public BigDecimal getSumme() { return getNettoGesamt(); }
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,7 @@ package de.hsmannheim.faktura.dokumente.domain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Steuert erlaubte Folgeaktionen im Dokumentenprozess.
|
* Steuert erlaubte Folgeaktionen im Dokumentenprozess.
|
||||||
*
|
* Workflow: ANGEBOT: OFFEN → UEBERFUEHRT | AB: BESTAETIGT | LS: GELIEFERT | R: FESTGESCHRIEBEN
|
||||||
* Workflow:
|
|
||||||
* ANGEBOT: OFFEN → UEBERFUEHRT
|
|
||||||
* AUFTRAGSBESTAETIGUNG: BESTAETIGT
|
|
||||||
* LIEFERSCHEIN: GELIEFERT
|
|
||||||
* RECHNUNG: FESTGESCHRIEBEN
|
|
||||||
*/
|
*/
|
||||||
public enum DokumentStatus {
|
public enum DokumentStatus {
|
||||||
OFFEN,
|
OFFEN,
|
||||||
|
|
@ -15,5 +10,17 @@ public enum DokumentStatus {
|
||||||
BESTAETIGT,
|
BESTAETIGT,
|
||||||
GELIEFERT,
|
GELIEFERT,
|
||||||
FAKTURIERT,
|
FAKTURIERT,
|
||||||
FESTGESCHRIEBEN
|
FESTGESCHRIEBEN;
|
||||||
|
|
||||||
|
/** Lesbarer Anzeigename für die GUI (PHGUI10). */
|
||||||
|
public String getAnzeigename() {
|
||||||
|
return switch (this) {
|
||||||
|
case OFFEN -> "Offen";
|
||||||
|
case UEBERFUEHRT -> "Überführt";
|
||||||
|
case BESTAETIGT -> "Bestätigt";
|
||||||
|
case GELIEFERT -> "Geliefert";
|
||||||
|
case FAKTURIERT -> "Fakturiert";
|
||||||
|
case FESTGESCHRIEBEN -> "Festgeschrieben";
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,3 +75,19 @@ public interface DokumentRepository {
|
||||||
*/
|
*/
|
||||||
int findMaxLaufendeNummer(String praefix, int jahr);
|
int findMaxLaufendeNummer(String praefix, int jahr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt alle gespeicherten Dokumente zurück (für die Listenansicht in der GUI).
|
||||||
|
*
|
||||||
|
* @return Liste aller Dokumente
|
||||||
|
*/
|
||||||
|
List<Dokument> findAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Löscht ein Dokument anhand seiner Nummer.
|
||||||
|
* Festgeschriebene Rechnungen können nicht gelöscht werden.
|
||||||
|
*
|
||||||
|
* @param nummer Dokumentnummer
|
||||||
|
* @return true wenn gelöscht, false wenn nicht gefunden
|
||||||
|
*/
|
||||||
|
boolean delete(String nummer);
|
||||||
|
|
|
||||||
|
|
@ -95,3 +95,13 @@ public class InMemoryDokumentRepository implements DokumentRepository {
|
||||||
store.clear();
|
store.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Dokument> findAll() {
|
||||||
|
return new ArrayList<>(store.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete(String nummer) {
|
||||||
|
return store.remove(nummer) != null;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
package de.hsmannheim.faktura.dokumente.service;
|
||||||
|
|
||||||
|
import de.hsmannheim.faktura.dokumente.domain.*;
|
||||||
|
import de.hsmannheim.faktura.dokumente.export.SimplePdfExportService;
|
||||||
|
import de.hsmannheim.faktura.dokumente.lookup.*;
|
||||||
|
import de.hsmannheim.faktura.dokumente.repository.DokumentRepository;
|
||||||
|
import de.hsmannheim.faktura.dokumente.repository.InMemoryDokumentRepository;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fassade für die GUI (DokumentPanel).
|
||||||
|
* Kapselt den DokumentServiceImpl und bietet die Methoden die die GUI braucht.
|
||||||
|
*
|
||||||
|
* Wird in der GUI so instanziiert:
|
||||||
|
* new DokumentenService(new InMemoryDokumentRepository())
|
||||||
|
*
|
||||||
|
* Sobald Gruppe G (Produkte) und H (Kunden) ihre Lookups liefern,
|
||||||
|
* können diese über den Setter-Konstruktor injiziert werden.
|
||||||
|
*/
|
||||||
|
public class DokumentenService {
|
||||||
|
|
||||||
|
private final DokumentService service;
|
||||||
|
private final DokumentRepository repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Konstruktor für die GUI – nimmt ein Repository entgegen.
|
||||||
|
* Produkt- und Kundenlookup werden als Stubs vorbelegt.
|
||||||
|
*/
|
||||||
|
public DokumentenService(DokumentRepository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
|
||||||
|
// Stub-Lookups bis Gruppe G und H ihre Implementierungen liefern
|
||||||
|
ProductLookup produktLookup = new StubProductLookup();
|
||||||
|
CustomerLookup kundeLookup = new StubCustomerLookup();
|
||||||
|
|
||||||
|
this.service = new DokumentServiceImpl(
|
||||||
|
repository,
|
||||||
|
produktLookup,
|
||||||
|
kundeLookup,
|
||||||
|
new SimplePdfExportService()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vollständiger Konstruktor – für Produktion wenn echte Lookups vorliegen.
|
||||||
|
*/
|
||||||
|
public DokumentenService(DokumentRepository repository,
|
||||||
|
ProductLookup produktLookup,
|
||||||
|
CustomerLookup kundeLookup) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.service = new DokumentServiceImpl(
|
||||||
|
repository, produktLookup, kundeLookup, new SimplePdfExportService()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Methoden für die GUI
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Alle Dokumente für die Listenansicht. */
|
||||||
|
public List<Dokument> getAllDokumente() {
|
||||||
|
return repository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Einzelnes Dokument nach Nummer laden. */
|
||||||
|
public Optional<Dokument> getDokumentByNummer(String nummer) {
|
||||||
|
return repository.findByNummer(nummer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dokument löschen. Festgeschriebene Rechnungen können nicht gelöscht werden.
|
||||||
|
* @return true wenn erfolgreich gelöscht
|
||||||
|
*/
|
||||||
|
public boolean deleteDokument(String nummer) {
|
||||||
|
Optional<Dokument> dok = repository.findByNummer(nummer);
|
||||||
|
if (dok.isEmpty()) return false;
|
||||||
|
if (dok.get().isFestgeschrieben()) return false; // PHGUI11
|
||||||
|
return repository.delete(nummer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Auftragsbestätigung aus Angebot erzeugen. */
|
||||||
|
public Auftragsbestaetigung createAuftragsbestaetigung(String angebotsNummer) {
|
||||||
|
return service.erstelleAuftragsbestaetigung(angebotsNummer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Lieferschein aus AB erzeugen (Lieferdatum = heute). */
|
||||||
|
public Lieferschein createLieferschein(String auftragsNummer) {
|
||||||
|
return service.erstelleLieferschein(auftragsNummer, LocalDate.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rechnung aus Lieferschein erzeugen. */
|
||||||
|
public Rechnung createRechnung(String lieferscheinNummer) {
|
||||||
|
return service.erstelleRechnung(lieferscheinNummer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** PDF-Export eines Dokuments. */
|
||||||
|
public Path exportPdf(String dokumentNummer, DokumentType typ) {
|
||||||
|
return service.exportiereAlsPdf(dokumentNummer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Stub-Implementierungen (Platzhalter bis Gruppe G und H fertig sind)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platzhalter-Produktlookup.
|
||||||
|
* Ersetzen durch echte Implementierung von Gruppe G.
|
||||||
|
*/
|
||||||
|
private static class StubProductLookup implements ProductLookup {
|
||||||
|
@Override
|
||||||
|
public Optional<ProductDto> findProduct(long produktId) {
|
||||||
|
// Beispieldaten bis Gruppe G ihre Implementierung liefert
|
||||||
|
return Optional.of(new ProductDto(
|
||||||
|
produktId,
|
||||||
|
"Produkt #" + produktId,
|
||||||
|
new BigDecimal("100.00"),
|
||||||
|
new BigDecimal("0.19")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platzhalter-Kundenlookup.
|
||||||
|
* Ersetzen durch echte Implementierung von Gruppe H.
|
||||||
|
*/
|
||||||
|
private static class StubCustomerLookup implements CustomerLookup {
|
||||||
|
@Override
|
||||||
|
public Optional<CustomerDto> findCustomer(long kundenId) {
|
||||||
|
// Beispieldaten bis Gruppe H ihre Implementierung liefert
|
||||||
|
return Optional.of(new CustomerDto(
|
||||||
|
kundenId,
|
||||||
|
"Kunde #" + kundenId,
|
||||||
|
"Musterstraße 1, 68163 Mannheim",
|
||||||
|
"DE123456789"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,69 +3,33 @@ package de.hsmannheim.faktura.gui;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.table.*;
|
import javax.swing.table.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import de.hsmannheim.faktura.dokumente.domain.Dokument;
|
import de.hsmannheim.faktura.dokumente.domain.Dokument;
|
||||||
import de.hsmannheim.faktura.dokumente.domain.DokumentPosition;
|
|
||||||
import de.hsmannheim.faktura.dokumente.domain.DokumentStatus;
|
import de.hsmannheim.faktura.dokumente.domain.DokumentStatus;
|
||||||
import de.hsmannheim.faktura.dokumente.domain.DokumentType;
|
import de.hsmannheim.faktura.dokumente.service.DokumentenService;
|
||||||
import de.hsmannheim.faktura.dokumente.export.PdfExportService;
|
|
||||||
import de.hsmannheim.faktura.dokumente.export.SimplePdfExportService;
|
|
||||||
import de.hsmannheim.faktura.dokumente.lookup.CustomerDto;
|
|
||||||
import de.hsmannheim.faktura.dokumente.lookup.CustomerLookup;
|
|
||||||
import de.hsmannheim.faktura.dokumente.lookup.ProductDto;
|
|
||||||
import de.hsmannheim.faktura.dokumente.lookup.ProductLookup;
|
|
||||||
import de.hsmannheim.faktura.dokumente.repository.DokumentRepository;
|
|
||||||
import de.hsmannheim.faktura.dokumente.repository.InMemoryDokumentRepository;
|
import de.hsmannheim.faktura.dokumente.repository.InMemoryDokumentRepository;
|
||||||
import de.hsmannheim.faktura.dokumente.service.DokumentService;
|
|
||||||
import de.hsmannheim.faktura.dokumente.service.DokumentServiceImpl;
|
|
||||||
import de.hsmannheim.faktura.kunde.repository.KundeRepositoryJson;
|
|
||||||
import de.hsmannheim.faktura.kunde.service.BelegReferenzPruefer;
|
|
||||||
import de.hsmannheim.faktura.kunde.service.KundeService;
|
|
||||||
import de.hsmannheim.faktura.kunde.service.KundeValidator;
|
|
||||||
import de.hsmannheim.faktura.kunde.model.Kunde;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel für den Dokumentenprozess (PHGUI10, PHGUI11, PHGUI12).
|
* Panel für den Dokumentenprozess (PHGUI10, PHGUI11, PHGUI12).
|
||||||
*
|
* Zeigt Status und zulässige Folgeaktionen an. Deaktiviert unzulässige Aktionen (PHGUI10).
|
||||||
* Verdrahtung gegen die spec-konforme Schnittstelle aus dem
|
* Festgeschriebene Rechnungen sind schreibgeschützt (PHGUI11).
|
||||||
* Pflichtenheft Gruppe F v1.0 (Kap. 6.2):
|
|
||||||
* - Service: {@link DokumentService} / {@link DokumentServiceImpl}
|
|
||||||
* - Repository: {@link DokumentRepository} / {@link InMemoryDokumentRepository}
|
|
||||||
* - Methoden: erstelleAuftragsbestaetigung / erstelleLieferschein /
|
|
||||||
* erstelleRechnung / exportiereAlsPdf
|
|
||||||
* - Status: OFFEN, UEBERFUEHRT, BESTAETIGT, GELIEFERT, FAKTURIERT,
|
|
||||||
* FESTGESCHRIEBEN
|
|
||||||
*
|
|
||||||
* Die ursprüngliche GUI-Verdrahtung (DokumentenService, getDokumentnummer,
|
|
||||||
* RECHNUNG_ERSTELLT, deleteDokument, ...) findet sich in keinem Pflichtenheft
|
|
||||||
* wieder und wurde hier auf die gemeinsame Spec gemappt. OP-6 (GUI vs.
|
|
||||||
* PH v1.1 / Gruppe F PH v1.0).
|
|
||||||
*/
|
*/
|
||||||
public class DokumentPanel extends JPanel {
|
public class DokumentPanel extends JPanel {
|
||||||
|
|
||||||
private final MainFrame mainFrame;
|
private final MainFrame mainFrame;
|
||||||
private final DokumentService dokumentService;
|
private final DokumentenService dokumentenService;
|
||||||
private final TrackingDokumentRepository tracking;
|
|
||||||
|
|
||||||
// Tabelle
|
// Tabelle
|
||||||
private DefaultTableModel tableModel;
|
private DefaultTableModel tableModel;
|
||||||
private JTable dokumentTable;
|
private JTable dokumentTable;
|
||||||
|
|
||||||
// Detailfelder (schreibgeschützt)
|
// Detailfelder (schreibgeschützt)
|
||||||
private JTextField txtDokumentNummer;
|
private JTextField txtDokumentnummer;
|
||||||
private JTextField txtKundenId;
|
private JTextField txtKundenId;
|
||||||
private JTextField txtDatum;
|
private JTextField txtDatum;
|
||||||
private JTextField txtStatus;
|
private JTextField txtStatus;
|
||||||
private JCheckBox chkFestgeschrieben;
|
private JCheckBox chkFestgeschrieben;
|
||||||
|
|
||||||
// Positionstabelle
|
// Positionstabelle
|
||||||
private DefaultTableModel posTableModel;
|
private DefaultTableModel posTableModel;
|
||||||
|
|
@ -78,6 +42,8 @@ public class DokumentPanel extends JPanel {
|
||||||
|
|
||||||
// Aktions-Buttons (PHGUI10)
|
// Aktions-Buttons (PHGUI10)
|
||||||
private JButton btnNeu;
|
private JButton btnNeu;
|
||||||
|
private JButton btnSpeichern;
|
||||||
|
private JButton btnLoeschen;
|
||||||
private JButton btnAbbrechen;
|
private JButton btnAbbrechen;
|
||||||
private JButton btnPdfExport;
|
private JButton btnPdfExport;
|
||||||
|
|
||||||
|
|
@ -90,53 +56,18 @@ public class DokumentPanel extends JPanel {
|
||||||
|
|
||||||
public DokumentPanel(MainFrame mainFrame) {
|
public DokumentPanel(MainFrame mainFrame) {
|
||||||
this.mainFrame = mainFrame;
|
this.mainFrame = mainFrame;
|
||||||
|
// FIX: InMemoryDokumentRepository statt DokumentRepository (Interface)
|
||||||
// DokumentServiceImpl braucht 4 Abhängigkeiten (DI laut Gruppe F):
|
this.dokumentenService = new DokumentenService(new InMemoryDokumentRepository());
|
||||||
// Repository, ProductLookup, CustomerLookup, PdfExportService.
|
|
||||||
this.tracking = new TrackingDokumentRepository(new InMemoryDokumentRepository());
|
|
||||||
PdfExportService pdfExport = new SimplePdfExportService(Path.of("exports"));
|
|
||||||
CustomerLookup customerLookup = new KundeCustomerLookup(buildKundeService());
|
|
||||||
ProductLookup productLookup = stubProductLookup();
|
|
||||||
|
|
||||||
this.dokumentService = new DokumentServiceImpl(
|
|
||||||
tracking, productLookup, customerLookup, pdfExport);
|
|
||||||
|
|
||||||
setLayout(new BorderLayout(8, 8));
|
setLayout(new BorderLayout(8, 8));
|
||||||
setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
||||||
initComponents();
|
initComponents();
|
||||||
ladeDokumente();
|
ladeDokumente();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* KundeService nur als Datenquelle für den CustomerLookup-Adapter
|
|
||||||
* (K3 aus PH v1.1). Eigener Aufbau, da das Panel self-contained ist –
|
|
||||||
* geteiltes Wiring zwischen Panels ist Bestandteil von OP-6.
|
|
||||||
*/
|
|
||||||
private KundeService buildKundeService() {
|
|
||||||
return new KundeService(
|
|
||||||
new KundeRepositoryJson(new File("data/kunden.json")),
|
|
||||||
new KundeValidator(),
|
|
||||||
(BelegReferenzPruefer) (kundeId -> false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DokumentPanel kann derzeit keine neuen Angebote anlegen
|
|
||||||
* (Eingabemaske fehlt im UI), deshalb wird der ProductLookup nicht
|
|
||||||
* aktiv genutzt. Stub ist ausreichend, damit DokumentServiceImpl
|
|
||||||
* verdrahtet werden kann.
|
|
||||||
*/
|
|
||||||
private ProductLookup stubProductLookup() {
|
|
||||||
return produktId -> Optional.<ProductDto>empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// UI-Aufbau
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
// --- Linke Seite: Dokumentenliste ---
|
// --- Linke Seite: Dokumentenliste ---
|
||||||
JPanel leftPanel = new JPanel(new BorderLayout(4, 4));
|
JPanel leftPanel = new JPanel(new BorderLayout(4, 4));
|
||||||
leftPanel.setPreferredSize(new Dimension(320, 0));
|
leftPanel.setPreferredSize(new Dimension(300, 0));
|
||||||
|
|
||||||
String[] cols = {"Nr.", "Typ", "Status"};
|
String[] cols = {"Nr.", "Typ", "Status"};
|
||||||
tableModel = new DefaultTableModel(cols, 0) {
|
tableModel = new DefaultTableModel(cols, 0) {
|
||||||
|
|
@ -146,9 +77,14 @@ public class DokumentPanel extends JPanel {
|
||||||
// Status-Spalte farbig (PHGUI10)
|
// Status-Spalte farbig (PHGUI10)
|
||||||
public Component prepareRenderer(TableCellRenderer r, int row, int col) {
|
public Component prepareRenderer(TableCellRenderer r, int row, int col) {
|
||||||
Component c = super.prepareRenderer(r, row, col);
|
Component c = super.prepareRenderer(r, row, col);
|
||||||
if (col == 2 && !isRowSelected(row)) {
|
if (col == 2) {
|
||||||
String status = String.valueOf(getValueAt(row, col));
|
String status = (String) getValueAt(row, col);
|
||||||
c.setForeground(farbeFuerStatus(status));
|
if (status != null) {
|
||||||
|
if (status.contains("Offen")) c.setForeground(new Color(41, 128, 185));
|
||||||
|
else if (status.contains("Bestätigt")) c.setForeground(new Color(39, 174, 96));
|
||||||
|
else if (status.contains("Festgeschr")) c.setForeground(new Color(192, 57, 43));
|
||||||
|
else c.setForeground(Color.BLACK);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
c.setForeground(Color.BLACK);
|
c.setForeground(Color.BLACK);
|
||||||
}
|
}
|
||||||
|
|
@ -157,266 +93,264 @@ public class DokumentPanel extends JPanel {
|
||||||
};
|
};
|
||||||
dokumentTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
dokumentTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
dokumentTable.setAutoCreateRowSorter(true);
|
dokumentTable.setAutoCreateRowSorter(true);
|
||||||
dokumentTable.getTableHeader().setReorderingAllowed(false);
|
|
||||||
dokumentTable.getSelectionModel().addListSelectionListener(e -> {
|
dokumentTable.getSelectionModel().addListSelectionListener(e -> {
|
||||||
if (!e.getValueIsAdjusting()) zeigeAusgewaehltes();
|
if (!e.getValueIsAdjusting()) zeigeAusgewaehltes();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
leftPanel.add(new JLabel("Dokumente"), BorderLayout.NORTH);
|
||||||
leftPanel.add(new JScrollPane(dokumentTable), BorderLayout.CENTER);
|
leftPanel.add(new JScrollPane(dokumentTable), BorderLayout.CENTER);
|
||||||
|
|
||||||
// --- Rechte Seite: Detailbereich ---
|
// --- Rechte Seite: Detailansicht ---
|
||||||
JPanel rightPanel = new JPanel(new BorderLayout(0, 8));
|
JPanel rightPanel = new JPanel(new BorderLayout(4, 8));
|
||||||
rightPanel.add(kopfPanel(), BorderLayout.NORTH);
|
|
||||||
rightPanel.add(positionsBereich(), BorderLayout.CENTER);
|
|
||||||
rightPanel.add(buttonPanel(), BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel);
|
JPanel headerPanel = new JPanel(new GridBagLayout());
|
||||||
split.setDividerLocation(320);
|
headerPanel.setBorder(BorderFactory.createTitledBorder("Dokumentdetail"));
|
||||||
add(split, BorderLayout.CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
private JPanel kopfPanel() {
|
|
||||||
JPanel p = new JPanel(new GridBagLayout());
|
|
||||||
p.setBorder(BorderFactory.createTitledBorder("Dokumentkopf"));
|
|
||||||
GridBagConstraints g = new GridBagConstraints();
|
GridBagConstraints g = new GridBagConstraints();
|
||||||
g.insets = new Insets(4, 6, 2, 6);
|
g.insets = new Insets(3, 4, 3, 4);
|
||||||
g.anchor = GridBagConstraints.WEST;
|
g.fill = GridBagConstraints.HORIZONTAL;
|
||||||
g.fill = GridBagConstraints.HORIZONTAL;
|
g.weightx = 0.5;
|
||||||
g.weightx = 1.0;
|
|
||||||
|
|
||||||
txtDokumentNummer = createReadOnlyField();
|
// Festgeschrieben-Checkbox (PHGUI11)
|
||||||
txtKundenId = createReadOnlyField();
|
chkFestgeschrieben = new JCheckBox("Festgeschrieben");
|
||||||
txtDatum = createReadOnlyField();
|
|
||||||
txtStatus = createReadOnlyField();
|
|
||||||
chkFestgeschrieben = new JCheckBox("Festgeschrieben (PHGUI11)");
|
|
||||||
chkFestgeschrieben.setEnabled(false);
|
chkFestgeschrieben.setEnabled(false);
|
||||||
|
g.gridx = 1; g.gridy = 0; g.anchor = GridBagConstraints.EAST;
|
||||||
|
headerPanel.add(chkFestgeschrieben, g);
|
||||||
|
|
||||||
int row = 0;
|
g.anchor = GridBagConstraints.WEST;
|
||||||
row = addLabelField(p, g, "Dokumentnummer:", txtDokumentNummer, row);
|
g.gridx = 0; g.gridy = 1; headerPanel.add(new JLabel("Dokumentnummer"), g);
|
||||||
row = addLabelField(p, g, "Kunden-ID:", txtKundenId, row);
|
g.gridx = 1; headerPanel.add(new JLabel("Kundennummer"), g);
|
||||||
row = addLabelField(p, g, "Datum:", txtDatum, row);
|
txtDokumentnummer = createReadOnlyField();
|
||||||
row = addLabelField(p, g, "Status:", txtStatus, row);
|
txtKundenId = createReadOnlyField();
|
||||||
|
g.gridx = 0; g.gridy = 2; headerPanel.add(txtDokumentnummer, g);
|
||||||
|
g.gridx = 1; headerPanel.add(txtKundenId, g);
|
||||||
|
|
||||||
g.gridx = 0; g.gridy = row; g.gridwidth = 2; p.add(chkFestgeschrieben, g);
|
g.gridx = 0; g.gridy = 3; headerPanel.add(new JLabel("Datum"), g);
|
||||||
g.gridwidth = 1;
|
g.gridx = 1; headerPanel.add(new JLabel("Status"), g);
|
||||||
return p;
|
txtDatum = createReadOnlyField();
|
||||||
}
|
txtStatus = createReadOnlyField();
|
||||||
|
g.gridx = 0; g.gridy = 4; headerPanel.add(txtDatum, g);
|
||||||
|
g.gridx = 1; headerPanel.add(txtStatus, g);
|
||||||
|
|
||||||
private JPanel positionsBereich() {
|
rightPanel.add(headerPanel, BorderLayout.NORTH);
|
||||||
JPanel p = new JPanel(new BorderLayout(0, 4));
|
|
||||||
p.setBorder(BorderFactory.createTitledBorder("Positionen / Summen"));
|
|
||||||
|
|
||||||
String[] posCols = {"Pos.", "Bezeichnung", "Menge", "Einzelpreis", "MwSt.", "Gesamt"};
|
// Positionstabelle
|
||||||
|
String[] posCols = {"Pos", "Bezeichnung", "Menge", "Einzelpreis", "MwSt.", "Summe"};
|
||||||
posTableModel = new DefaultTableModel(posCols, 0) {
|
posTableModel = new DefaultTableModel(posCols, 0) {
|
||||||
public boolean isCellEditable(int r, int c) { return false; }
|
public boolean isCellEditable(int r, int c) { return false; }
|
||||||
};
|
};
|
||||||
posTable = new JTable(posTableModel);
|
posTable = new JTable(posTableModel);
|
||||||
posTable.getTableHeader().setReorderingAllowed(false);
|
posTable.setEnabled(false);
|
||||||
p.add(new JScrollPane(posTable), BorderLayout.CENTER);
|
|
||||||
|
|
||||||
JPanel summenPanel = new JPanel(new GridLayout(1, 6, 8, 0));
|
JPanel posPanel = new JPanel(new BorderLayout());
|
||||||
summenPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
|
posPanel.setBorder(BorderFactory.createTitledBorder("Positionen:"));
|
||||||
summenPanel.add(new JLabel("Netto:"));
|
posPanel.add(new JScrollPane(posTable), BorderLayout.CENTER);
|
||||||
lblNetto = new JLabel("0.00 €");
|
|
||||||
summenPanel.add(lblNetto);
|
|
||||||
summenPanel.add(new JLabel("USt.:"));
|
|
||||||
lblUst = new JLabel("0.00 €");
|
|
||||||
summenPanel.add(lblUst);
|
|
||||||
summenPanel.add(new JLabel("Brutto:"));
|
|
||||||
lblBrutto = new JLabel("0.00 €");
|
|
||||||
summenPanel.add(lblBrutto);
|
|
||||||
p.add(summenPanel, BorderLayout.SOUTH);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JPanel buttonPanel() {
|
// Summen
|
||||||
JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 4));
|
JPanel summenPanel = new JPanel(new GridLayout(3, 2, 4, 2));
|
||||||
|
summenPanel.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
|
||||||
|
lblNetto = new JLabel("0,00 €"); lblNetto.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||||
|
lblUst = new JLabel("0,00 €"); lblUst.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||||
|
lblBrutto = new JLabel("0,00 €", SwingConstants.RIGHT);
|
||||||
|
lblBrutto.setFont(new Font("SansSerif", Font.BOLD, 13));
|
||||||
|
summenPanel.add(new JLabel("Netto:")); summenPanel.add(lblNetto);
|
||||||
|
summenPanel.add(new JLabel("USt.:")); summenPanel.add(lblUst);
|
||||||
|
summenPanel.add(new JLabel("Brutto:")); summenPanel.add(lblBrutto);
|
||||||
|
|
||||||
btnNeu = new JButton("Auswahl zurücksetzen");
|
JPanel mittelPanel = new JPanel(new BorderLayout());
|
||||||
btnAbbrechen = new JButton("Abbrechen");
|
mittelPanel.add(posPanel, BorderLayout.CENTER);
|
||||||
btnPdfExport = new JButton("PDF-Export");
|
mittelPanel.add(summenPanel, BorderLayout.SOUTH);
|
||||||
btnAngebotZuAuftrag = new JButton("→ Auftragsbestätigung");
|
rightPanel.add(mittelPanel, BorderLayout.CENTER);
|
||||||
btnAuftragZuLieferschein = new JButton("→ Lieferschein");
|
|
||||||
btnLieferscheinZuRechnung = new JButton("→ Rechnung");
|
|
||||||
|
|
||||||
|
// --- Aktionen (PHGUI10: nur zulässige aktiv) ---
|
||||||
|
JPanel aktionenPanel = new JPanel(new BorderLayout());
|
||||||
|
aktionenPanel.setBorder(BorderFactory.createTitledBorder("Aktionen:"));
|
||||||
|
|
||||||
|
JPanel stdButtons = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||||
|
btnNeu = new JButton("Neu");
|
||||||
|
btnSpeichern = new JButton("Speichern");
|
||||||
|
btnLoeschen = new JButton("Löschen");
|
||||||
|
btnAbbrechen = new JButton("Abbrechen");
|
||||||
|
btnPdfExport = new JButton("PDF-Export");
|
||||||
|
btnPdfExport.setBackground(new Color(41, 128, 185));
|
||||||
|
btnPdfExport.setForeground(Color.WHITE);
|
||||||
|
stdButtons.add(btnNeu);
|
||||||
|
stdButtons.add(btnSpeichern);
|
||||||
|
stdButtons.add(btnLoeschen);
|
||||||
|
stdButtons.add(btnAbbrechen);
|
||||||
|
stdButtons.add(btnPdfExport);
|
||||||
|
|
||||||
|
JPanel folgeButtons = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||||
|
btnAngebotZuAuftrag = new JButton("→ Auftragsbestätigung erstellen");
|
||||||
|
btnAuftragZuLieferschein = new JButton("→ Lieferschein erstellen");
|
||||||
|
btnLieferscheinZuRechnung = new JButton("→ Rechnung erstellen");
|
||||||
|
folgeButtons.add(btnAngebotZuAuftrag);
|
||||||
|
folgeButtons.add(btnAuftragZuLieferschein);
|
||||||
|
folgeButtons.add(btnLieferscheinZuRechnung);
|
||||||
|
|
||||||
|
aktionenPanel.add(stdButtons, BorderLayout.NORTH);
|
||||||
|
aktionenPanel.add(folgeButtons, BorderLayout.SOUTH);
|
||||||
|
rightPanel.add(aktionenPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
// Button-Actions
|
||||||
btnNeu.addActionListener(e -> neuesFormular());
|
btnNeu.addActionListener(e -> neuesFormular());
|
||||||
btnAbbrechen.addActionListener(e -> neuesFormular());
|
btnAbbrechen.addActionListener(e -> { neuesFormular(); ladeDokumente(); });
|
||||||
btnPdfExport.addActionListener(e -> pdfExport());
|
btnPdfExport.addActionListener(e -> pdfExport());
|
||||||
btnAngebotZuAuftrag.addActionListener(e ->
|
btnLoeschen.addActionListener(e -> loeschen());
|
||||||
folgeaktion(DokumentType.ANGEBOT));
|
|
||||||
btnAuftragZuLieferschein.addActionListener(e ->
|
|
||||||
folgeaktion(DokumentType.AUFTRAGSBESTAETIGUNG));
|
|
||||||
btnLieferscheinZuRechnung.addActionListener(e ->
|
|
||||||
folgeaktion(DokumentType.LIEFERSCHEIN));
|
|
||||||
|
|
||||||
p.add(btnAngebotZuAuftrag);
|
btnAngebotZuAuftrag.addActionListener(e -> folgeaktion("ANGEBOT_ZU_AUFTRAG"));
|
||||||
p.add(btnAuftragZuLieferschein);
|
btnAuftragZuLieferschein.addActionListener(e -> folgeaktion("AUFTRAG_ZU_LIEFERSCHEIN"));
|
||||||
p.add(btnLieferscheinZuRechnung);
|
btnLieferscheinZuRechnung.addActionListener(e -> folgeaktion("LIEFERSCHEIN_ZU_RECHNUNG"));
|
||||||
p.add(btnPdfExport);
|
|
||||||
p.add(btnNeu);
|
|
||||||
p.add(btnAbbrechen);
|
|
||||||
|
|
||||||
// Initial alles deaktiviert (es ist nichts ausgewählt)
|
|
||||||
setAktionenDeaktiviert();
|
setAktionenDeaktiviert();
|
||||||
return p;
|
|
||||||
|
JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel);
|
||||||
|
split.setDividerLocation(300);
|
||||||
|
add(split, BorderLayout.CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int addLabelField(JPanel p, GridBagConstraints g,
|
// --- Daten ---
|
||||||
String label, JComponent field, int row) {
|
|
||||||
g.weighty = 0;
|
|
||||||
g.gridx = 0; g.gridy = row; g.weightx = 0; p.add(new JLabel(label), g);
|
|
||||||
g.gridx = 1; g.gridy = row; g.weightx = 1.0; p.add(field, g);
|
|
||||||
return row + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// Daten laden / anzeigen
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private void ladeDokumente() {
|
private void ladeDokumente() {
|
||||||
tableModel.setRowCount(0);
|
tableModel.setRowCount(0);
|
||||||
for (Dokument d : tracking.findAll()) {
|
List<Dokument> alle = dokumentenService.getAllDokumente();
|
||||||
|
for (Dokument d : alle) {
|
||||||
tableModel.addRow(new Object[]{
|
tableModel.addRow(new Object[]{
|
||||||
d.getDokumentNummer(),
|
d.getDokumentNummer(), // FIX: getDokumentNummer() statt getDokumentnummer()
|
||||||
typBezeichnung(d.getTyp()),
|
d.getTypBezeichnung(),
|
||||||
d.getStatus().name()
|
d.getStatus().getAnzeigename()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void zeigeAusgewaehltes() {
|
private void zeigeAusgewaehltes() {
|
||||||
int row = dokumentTable.getSelectedRow();
|
int row = dokumentTable.getSelectedRow();
|
||||||
if (row < 0) { aktuellesDokument = null; return; }
|
if (row < 0) return;
|
||||||
int modelRow = dokumentTable.convertRowIndexToModel(row);
|
int modelRow = dokumentTable.convertRowIndexToModel(row);
|
||||||
String nr = (String) tableModel.getValueAt(modelRow, 0);
|
String nr = (String) tableModel.getValueAt(modelRow, 0);
|
||||||
|
|
||||||
tracking.findByNummer(nr).ifPresent(this::zeigeDokument);
|
dokumentenService.getDokumentByNummer(nr).ifPresent(d -> {
|
||||||
}
|
aktuellesDokument = d;
|
||||||
|
txtDokumentnummer.setText(d.getDokumentNummer()); // FIX
|
||||||
|
txtKundenId.setText(String.valueOf(d.getKundenId())); // FIX
|
||||||
|
txtDatum.setText(d.getDatum().toString());
|
||||||
|
txtStatus.setText(d.getStatus().getAnzeigename());
|
||||||
|
|
||||||
private void zeigeDokument(Dokument d) {
|
chkFestgeschrieben.setSelected(d.isFestgeschrieben());
|
||||||
aktuellesDokument = d;
|
|
||||||
txtDokumentNummer.setText(d.getDokumentNummer());
|
|
||||||
txtKundenId.setText(Long.toString(d.getKundenId()));
|
|
||||||
txtDatum.setText(d.getDatum() == null ? "" : d.getDatum().toString());
|
|
||||||
txtStatus.setText(d.getStatus().name());
|
|
||||||
|
|
||||||
boolean festgeschrieben = d.getStatus() == DokumentStatus.FESTGESCHRIEBEN;
|
// Positionen laden
|
||||||
chkFestgeschrieben.setSelected(festgeschrieben);
|
posTableModel.setRowCount(0);
|
||||||
|
int pos = 1;
|
||||||
// Positionen
|
for (var position : d.getPositionen()) {
|
||||||
posTableModel.setRowCount(0);
|
posTableModel.addRow(new Object[]{
|
||||||
int pos = 1;
|
|
||||||
boolean lieferschein = d.getTyp() == DokumentType.LIEFERSCHEIN; // PH-DP-07
|
|
||||||
for (DokumentPosition p : d.getPositionen()) {
|
|
||||||
posTableModel.addRow(new Object[]{
|
|
||||||
pos++,
|
pos++,
|
||||||
p.getBezeichnungSnapshot(),
|
position.getBezeichnungSnapshot(), // FIX
|
||||||
p.getMenge(),
|
position.getMenge(),
|
||||||
lieferschein ? "—" : (p.getEinzelpreisNettoSnapshot() + " €"),
|
position.getEinzelpreisNettoSnapshot() + " €", // FIX
|
||||||
lieferschein ? "—" : (formatProzent(p.getMwstSatzSnapshot())),
|
position.getMwstSatzSnapshot().multiply(java.math.BigDecimal.valueOf(100))
|
||||||
lieferschein ? "—" : (p.getNettoGesamt() + " €")
|
.setScale(0, java.math.RoundingMode.HALF_UP) + "%",// FIX
|
||||||
});
|
position.getNettoGesamt() + " €" // FIX
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Summen (Lieferschein zeigt keine Preise – PH-DP-07)
|
// Summen (nicht für Lieferschein)
|
||||||
if (lieferschein) {
|
if (d.getNettoSumme() != null) { // FIX
|
||||||
lblNetto.setText("—");
|
lblNetto.setText(d.getNettoSumme().toPlainString() + " €"); // FIX
|
||||||
lblUst.setText("—");
|
lblUst.setText(d.getUstSumme().toPlainString() + " €");
|
||||||
lblBrutto.setText("—");
|
lblBrutto.setText(d.getBruttoSumme().toPlainString() + " €"); // FIX
|
||||||
} else {
|
}
|
||||||
lblNetto.setText(nullSichBd(d.getNettoSumme()) + " €");
|
|
||||||
lblUst.setText( nullSichBd(d.getUstSumme()) + " €");
|
|
||||||
lblBrutto.setText(nullSichBd(d.getBruttoSumme())+ " €");
|
|
||||||
}
|
|
||||||
|
|
||||||
aktualisiereAktionen(d);
|
aktualisiereAktionen(d);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private String nullSichBd(BigDecimal v) { return v == null ? "0.00" : v.toPlainString(); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aktiviert nur die zulässigen Folgeaktionen basierend auf
|
* Aktiviert nur zulässige Folgeaktionen basierend auf Dokumentstatus (PHGUI10).
|
||||||
* Dokumenttyp und -status (PHGUI10).
|
* Festgeschriebene Rechnungen: nur PDF-Export aktiv (PHGUI11).
|
||||||
* Festgeschriebene Rechnungen: alle Aktionen außer PDF-Export
|
|
||||||
* deaktiviert (PHGUI11).
|
|
||||||
*/
|
*/
|
||||||
private void aktualisiereAktionen(Dokument d) {
|
private void aktualisiereAktionen(Dokument d) {
|
||||||
DokumentType typ = d.getTyp();
|
|
||||||
DokumentStatus status = d.getStatus();
|
DokumentStatus status = d.getStatus();
|
||||||
|
boolean festgeschrieben = d.isFestgeschrieben();
|
||||||
|
|
||||||
if (status == DokumentStatus.FESTGESCHRIEBEN) {
|
// PHGUI11: Festgeschriebene Rechnung → nur PDF-Export
|
||||||
|
if (festgeschrieben) {
|
||||||
|
btnNeu.setEnabled(true);
|
||||||
|
btnSpeichern.setEnabled(false);
|
||||||
|
btnLoeschen.setEnabled(false);
|
||||||
|
btnAbbrechen.setEnabled(true);
|
||||||
|
btnPdfExport.setEnabled(true); // PHGUI12
|
||||||
btnAngebotZuAuftrag.setEnabled(false);
|
btnAngebotZuAuftrag.setEnabled(false);
|
||||||
btnAuftragZuLieferschein.setEnabled(false);
|
btnAuftragZuLieferschein.setEnabled(false);
|
||||||
btnLieferscheinZuRechnung.setEnabled(false);
|
btnLieferscheinZuRechnung.setEnabled(false);
|
||||||
btnPdfExport.setEnabled(true); // PHGUI12
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
btnPdfExport.setEnabled(true);
|
// PHGUI10: Folgeaktionen je nach Status (FIX: korrekte Status-Konstanten)
|
||||||
btnAngebotZuAuftrag.setEnabled(
|
btnNeu.setEnabled(true);
|
||||||
typ == DokumentType.ANGEBOT && status == DokumentStatus.OFFEN);
|
btnSpeichern.setEnabled(true);
|
||||||
btnAuftragZuLieferschein.setEnabled(
|
btnLoeschen.setEnabled(true);
|
||||||
typ == DokumentType.AUFTRAGSBESTAETIGUNG && status == DokumentStatus.BESTAETIGT);
|
btnAbbrechen.setEnabled(true);
|
||||||
btnLieferscheinZuRechnung.setEnabled(
|
btnPdfExport.setEnabled(status == DokumentStatus.FESTGESCHRIEBEN); // FIX
|
||||||
typ == DokumentType.LIEFERSCHEIN && status == DokumentStatus.GELIEFERT);
|
|
||||||
|
btnAngebotZuAuftrag.setEnabled(status == DokumentStatus.OFFEN); // FIX
|
||||||
|
btnAuftragZuLieferschein.setEnabled(status == DokumentStatus.BESTAETIGT); // FIX
|
||||||
|
btnLieferscheinZuRechnung.setEnabled(status == DokumentStatus.GELIEFERT); // FIX
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAktionenDeaktiviert() {
|
private void setAktionenDeaktiviert() {
|
||||||
|
btnSpeichern.setEnabled(false);
|
||||||
|
btnLoeschen.setEnabled(false);
|
||||||
btnPdfExport.setEnabled(false);
|
btnPdfExport.setEnabled(false);
|
||||||
btnAngebotZuAuftrag.setEnabled(false);
|
btnAngebotZuAuftrag.setEnabled(false);
|
||||||
btnAuftragZuLieferschein.setEnabled(false);
|
btnAuftragZuLieferschein.setEnabled(false);
|
||||||
btnLieferscheinZuRechnung.setEnabled(false);
|
btnLieferscheinZuRechnung.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// Aktionen
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private void neuesFormular() {
|
private void neuesFormular() {
|
||||||
aktuellesDokument = null;
|
aktuellesDokument = null;
|
||||||
dokumentTable.clearSelection();
|
txtDokumentnummer.setText(""); txtKundenId.setText("");
|
||||||
txtDokumentNummer.setText("");
|
txtDatum.setText(""); txtStatus.setText("");
|
||||||
txtKundenId.setText("");
|
|
||||||
txtDatum.setText("");
|
|
||||||
txtStatus.setText("");
|
|
||||||
chkFestgeschrieben.setSelected(false);
|
chkFestgeschrieben.setSelected(false);
|
||||||
posTableModel.setRowCount(0);
|
posTableModel.setRowCount(0);
|
||||||
lblNetto.setText("0.00 €");
|
lblNetto.setText("0,00 €"); lblUst.setText("0,00 €"); lblBrutto.setText("0,00 €");
|
||||||
lblUst.setText("0.00 €");
|
|
||||||
lblBrutto.setText("0.00 €");
|
|
||||||
setAktionenDeaktiviert();
|
setAktionenDeaktiviert();
|
||||||
|
btnNeu.setEnabled(true); btnAbbrechen.setEnabled(true);
|
||||||
|
dokumentTable.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void loeschen() {
|
||||||
* Erzeugt das spec-konforme Folgedokument zum aktuell ausgewählten
|
|
||||||
* Dokument. PH-DP-04 / PH-DP-06 / PH-DP-08.
|
|
||||||
*/
|
|
||||||
private void folgeaktion(DokumentType erwartet) {
|
|
||||||
if (aktuellesDokument == null) {
|
if (aktuellesDokument == null) {
|
||||||
mainFrame.showStatus("Kein Dokument ausgewählt.");
|
mainFrame.showStatus("Kein Dokument ausgewählt.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (aktuellesDokument.getTyp() != erwartet) {
|
int confirm = JOptionPane.showConfirmDialog(
|
||||||
mainFrame.showStatus("Aktion passt nicht zum Dokumenttyp.");
|
this, "Dokument wirklich löschen?", "Löschen bestätigen",
|
||||||
return;
|
JOptionPane.YES_NO_OPTION
|
||||||
|
);
|
||||||
|
if (confirm != JOptionPane.YES_OPTION) return;
|
||||||
|
|
||||||
|
boolean deleted = dokumentenService.deleteDokument(aktuellesDokument.getDokumentNummer()); // FIX
|
||||||
|
if (deleted) {
|
||||||
|
ladeDokumente(); neuesFormular();
|
||||||
|
mainFrame.showStatus("Dokument gelöscht.");
|
||||||
|
} else {
|
||||||
|
mainFrame.showStatus("Dokument kann nicht gelöscht werden (z. B. festgeschriebene Rechnung).");
|
||||||
}
|
}
|
||||||
String quellNr = aktuellesDokument.getDokumentNummer();
|
}
|
||||||
|
|
||||||
|
private void folgeaktion(String typ) {
|
||||||
|
if (aktuellesDokument == null) return;
|
||||||
try {
|
try {
|
||||||
Dokument folge;
|
switch (typ) {
|
||||||
switch (erwartet) {
|
case "ANGEBOT_ZU_AUFTRAG" ->
|
||||||
case ANGEBOT ->
|
dokumentenService.createAuftragsbestaetigung(aktuellesDokument.getDokumentNummer()); // FIX
|
||||||
folge = dokumentService.erstelleAuftragsbestaetigung(quellNr); // PH-DP-04
|
case "AUFTRAG_ZU_LIEFERSCHEIN" ->
|
||||||
case AUFTRAGSBESTAETIGUNG ->
|
dokumentenService.createLieferschein(aktuellesDokument.getDokumentNummer()); // FIX
|
||||||
folge = dokumentService.erstelleLieferschein(quellNr, LocalDate.now()); // PH-DP-06
|
case "LIEFERSCHEIN_ZU_RECHNUNG" ->
|
||||||
case LIEFERSCHEIN ->
|
dokumentenService.createRechnung(aktuellesDokument.getDokumentNummer()); // FIX
|
||||||
folge = dokumentService.erstelleRechnung(quellNr); // PH-DP-08
|
|
||||||
default -> { mainFrame.showStatus("Kein Folgedokument vorgesehen."); return; }
|
|
||||||
}
|
}
|
||||||
ladeDokumente();
|
ladeDokumente();
|
||||||
mainFrame.showStatus("Folgedokument erstellt: " + folge.getDokumentNummer());
|
mainFrame.showStatus("Folgedokument erfolgreich erstellt.");
|
||||||
} catch (RuntimeException ex) {
|
} catch (Exception ex) {
|
||||||
// Fängt IllegalStateException, DuplicateDocumentException,
|
|
||||||
// ValidationException, DokumentNotFoundException
|
|
||||||
mainFrame.showStatus("Fehler: " + ex.getMessage());
|
mainFrame.showStatus("Fehler: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -427,128 +361,18 @@ public class DokumentPanel extends JPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Path pfad = dokumentService.exportiereAlsPdf(
|
dokumentenService.exportPdf(
|
||||||
aktuellesDokument.getDokumentNummer()); // PHGUI12 / PH-DP-12
|
aktuellesDokument.getDokumentNummer(), aktuellesDokument.getTyp()); // FIX
|
||||||
mainFrame.showStatus("PDF erzeugt: " + pfad);
|
mainFrame.showStatus("PDF-Export erfolgreich.");
|
||||||
} catch (RuntimeException ex) {
|
} catch (Exception ex) {
|
||||||
mainFrame.showStatus("PDF-Export fehlgeschlagen: " + ex.getMessage());
|
mainFrame.showStatus("PDF-Export fehlgeschlagen: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// Helfer
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private static String typBezeichnung(DokumentType t) {
|
|
||||||
if (t == null) return "";
|
|
||||||
return switch (t) {
|
|
||||||
case ANGEBOT -> "Angebot";
|
|
||||||
case AUFTRAGSBESTAETIGUNG -> "Auftragsbestätigung";
|
|
||||||
case LIEFERSCHEIN -> "Lieferschein";
|
|
||||||
case RECHNUNG -> "Rechnung";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Color farbeFuerStatus(String status) {
|
|
||||||
return switch (status) {
|
|
||||||
case "OFFEN", "BESTAETIGT" -> new Color(41, 128, 185);
|
|
||||||
case "GELIEFERT" -> new Color(39, 174, 96);
|
|
||||||
case "FESTGESCHRIEBEN" -> new Color(155, 89, 182);
|
|
||||||
case "UEBERFUEHRT", "FAKTURIERT" -> new Color(127, 140, 141);
|
|
||||||
default -> Color.BLACK;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String formatProzent(BigDecimal mwstSatz) {
|
|
||||||
if (mwstSatz == null) return "";
|
|
||||||
return mwstSatz.multiply(BigDecimal.valueOf(100)) + " %";
|
|
||||||
}
|
|
||||||
|
|
||||||
private JTextField createReadOnlyField() {
|
private JTextField createReadOnlyField() {
|
||||||
JTextField f = new JTextField();
|
JTextField f = new JTextField();
|
||||||
f.setEditable(false);
|
f.setEditable(false);
|
||||||
f.setBackground(new Color(230, 230, 230));
|
f.setBackground(new Color(230, 230, 230));
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// =========================================================================
|
|
||||||
// Adapter / Wrapper – GUI-intern, keine Eingriffe in fremde Module
|
|
||||||
// =========================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter K3 (PH v1.1 Kap. 6.2): Bedient die von Gruppe F geforderte
|
|
||||||
* {@link CustomerLookup}-Schnittstelle über das spec-konforme
|
|
||||||
* {@link KundeService} der Kundenverwaltung.
|
|
||||||
*/
|
|
||||||
private static final class KundeCustomerLookup implements CustomerLookup {
|
|
||||||
private final KundeService kundeService;
|
|
||||||
KundeCustomerLookup(KundeService kundeService) {
|
|
||||||
this.kundeService = kundeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<CustomerDto> findCustomer(long kundenId) {
|
|
||||||
return kundeService.finde(kundenId).map(this::toDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CustomerDto toDto(Kunde k) {
|
|
||||||
String name;
|
|
||||||
if (k.getFirmenname() != null && !k.getFirmenname().isBlank()) {
|
|
||||||
name = k.getFirmenname();
|
|
||||||
} else {
|
|
||||||
String n = k.getNachname() == null ? "" : k.getNachname();
|
|
||||||
name = (k.getVorname() == null || k.getVorname().isBlank())
|
|
||||||
? n : (k.getVorname() + " " + n);
|
|
||||||
}
|
|
||||||
String anschrift = String.format("%s, %s %s",
|
|
||||||
nullAls(k.getStrasse()),
|
|
||||||
nullAls(k.getPlz()),
|
|
||||||
nullAls(k.getOrt()));
|
|
||||||
return new CustomerDto(k.getKundeId(), name, anschrift, nullAls(k.getUstIdNr()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String nullAls(String s) { return s == null ? "" : s; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorator über {@link DokumentRepository}: trackt zusätzlich alle
|
|
||||||
* gespeicherten Dokumente, damit das Panel eine vollständige Liste
|
|
||||||
* anzeigen kann. {@code findByNummer/findByKunde/...} werden an das
|
|
||||||
* gekapselte Repository delegiert.
|
|
||||||
*
|
|
||||||
* Notwendig, weil das Schnittstellen-Interface kein {@code findAll()}
|
|
||||||
* vorsieht (Gruppe F PH v1.0 Kap. 6.2) – ein Tracking in der GUI ist
|
|
||||||
* spec-neutral und greift nicht in Gruppe F's Modul ein.
|
|
||||||
*/
|
|
||||||
private static final class TrackingDokumentRepository implements DokumentRepository {
|
|
||||||
private final DokumentRepository delegate;
|
|
||||||
private final List<Dokument> alle = new ArrayList<>();
|
|
||||||
|
|
||||||
TrackingDokumentRepository(DokumentRepository delegate) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Dokument> findAll() {
|
|
||||||
List<Dokument> kopie = new ArrayList<>(alle);
|
|
||||||
kopie.sort(Comparator
|
|
||||||
.comparing(Dokument::getDatum, Comparator.nullsLast(Comparator.naturalOrder()))
|
|
||||||
.thenComparing(Dokument::getDokumentNummer));
|
|
||||||
return Collections.unmodifiableList(kopie);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save(Dokument dokument) {
|
|
||||||
delegate.save(dokument);
|
|
||||||
if (!alle.contains(dokument)) {
|
|
||||||
alle.add(dokument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Optional<Dokument> findByNummer(String nummer) { return delegate.findByNummer(nummer); }
|
|
||||||
@Override public List<Dokument> findByKunde(long kundenId) { return delegate.findByKunde(kundenId); }
|
|
||||||
@Override public boolean existsFolgedokument(String quellDokumentNr) { return delegate.existsFolgedokument(quellDokumentNr); }
|
|
||||||
@Override public boolean existsReferencedProdukt(long produktId) { return delegate.existsReferencedProdukt(produktId); }
|
|
||||||
@Override public boolean existsReferencedKunde(long kundenId) { return delegate.existsReferencedKunde(kundenId); }
|
|
||||||
@Override public int findMaxLaufendeNummer(String praefix, int j) { return delegate.findMaxLaufendeNummer(praefix, j); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue