Skip to content

Method: lambda$getSla$0(Dokumentenklasse)

1: package auftraege;
2:
3: import auftraege.auftragsBildungsParameter.BeilagenArten;
4: import auftraege.auftragsBildungsParameter.abstraction.DokumentenklassenVariable;
5: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.ProzessModell;
6: import maschine.Maschine;
7: import maschine.faehigkeit.DruckTyp;
8: import maschine.faehigkeit.Drucken;
9: import maschine.faehigkeit.FaehigkeitVisitor;
10: import maschine.faehigkeit.FarbDruckTyp;
11: import maschine.faehigkeit.Kuvertieren;
12: import maschine.faehigkeit.MaschinenFaehigkeit;
13: import maschine.faehigkeit.SimplesDrucken;
14: import maschine.faehigkeit.SimplesKuvertieren;
15: import material.MaterialMitMessung;
16: import material.kuvert.KuvertFormat;
17: import mensch.Mitarbeiter;
18: import util.ClassObjectMap;
19: import util.Immutable;
20: import util.Pair;
21: import zeit.eintraege.MaschinenBelegungEintrag;
22: import zeit.eintraege.MenschBelegungEintrag;
23:
24: import java.time.LocalDateTime;
25: import java.util.Collections;
26: import java.util.Comparator;
27: import java.util.HashMap;
28: import java.util.List;
29: import java.util.Map;
30: import java.util.NoSuchElementException;
31: import java.util.Set;
32: import java.util.stream.Collectors;
33: import java.util.stream.Stream;
34:
35: /**
36: * <p>
37: * Produktionsaufträge setzten sich aus einer oder mehreren Dokumentenklassen zusammen. Ziel dieser Bündelung soll es sein, dass mehrere Kundenaufträge gebündelt
38: * verarbeitet werden können. Dadurch werden Papierrollen und die eingesetzten Maschinen besser ausgenutzt. Würde jeder Auftrag separat gedruckt werden, entstünde viel
39: * Verschnitt und erhöhte Rüstzeiten für Maschinen. Durch eine Zusammenfassung von Kundenaufträgen kann Zeit und somit auch Geld eingespart werden. Erst durch die
40: * Zusammenfassung bringt der Auftragnehmer seinen Kunden Vorteile durch mögliche Einsparungen im Bereich des Drucks, des Versandes und der Zustellung durch umfangreiche
41: * Massenverarbeitung.
42: * </p>
43: *
44: * <p>
45: * Bei der Erstellung der einzelnen Produktionsaufträge sind die Eigenschaften der Dokumentenklassen ausschlaggebend, da hier die notwendigen Rahmenbedingungen erfasst
46: * und definiert sind.
47: * </p>
48: */
49: @Immutable
50: public class ProduktionsAuftrag {
51:         
52:         private final List<Dokumentenklasse> dokumentenklassen;
53:         private final Map<Maschine, MaschinenBelegungEintrag> maschinenBelegungen;
54:         
55:         private final Map<Pair<Mitarbeiter, MaschinenFaehigkeit>, MenschBelegungEintrag> menschBelegungen;
56:         
57:         /**
58:          * Erstellt einen neuen {@link ProduktionsAuftrag}, der die übergebenen {@link Dokumentenklasse} enthält.
59:          *
60:          * @param klassen
61:          *                 die enthaltenden Klassen.
62:          */
63:         public ProduktionsAuftrag(final List<Dokumentenklasse> klassen) {
64:                 this.dokumentenklassen = klassen;
65:                 this.maschinenBelegungen = new HashMap<>();
66:                 this.menschBelegungen = new HashMap<>();
67:         }
68:         
69:         /**
70:          * Liefert die enthaltenden Dokumentenklassen.
71:          *
72:          * @return Dokumentenklassen.
73:          */
74:         public List<Dokumentenklasse> getDokumentenklassen() {
75:                 return this.dokumentenklassen;
76:         }
77:         
78:         /**
79:          * Liefert die Anzahl der Blätter zurück.
80:          *
81:          * @return Sie Summe der Blätter der Dokumentenklassen.
82:          */
83:         public int getAnzahlBlaetter() {
84:                 return this.dokumentenklassen.stream().mapToInt(Dokumentenklasse::getAnzahlBlaetter).sum();
85:         }
86:         
87:         /**
88:          * @return Anzahl der Sendungen in dem Produktionsauftrag. Mindestens eins
89:          */
90:         public int getAnzahlSendungen() {
91:                 return this.dokumentenklassen.stream().mapToInt(Dokumentenklasse::getAnzahlSendungen).sum();
92:         }
93:         
94:         /**
95:          * @return liefert das {@link ServiceLevelAgreement} des {@link ProduktionsAuftrag ProduktionsAuftrags}
96:          */
97:         public ServiceLevelAgreement getSla() {
98:                 return this.dokumentenklassen.stream().min(Comparator.comparing(dokumentenklasse -> dokumentenklasse.getSla().getFrist(dokumentenklasse)))
99:                                 .map(Dokumentenklasse::getSla).orElse(ServiceLevelAgreement.MAX_VALUE);
100:         }
101:         
102:         /**
103:          * Liefert den größten Drucktyp (nach Reihenfolge der definition) der {@link DokumentenklassenVariable}n der in diesem Produktionsauftrag enthaltenen {@link
104:          * Dokumentenklasse}n. Ist kein Drucktyp vorhanden, so wird ein {@link DruckTyp#duplex Duplex} geliefert.
105:          *
106:          * @return größter Drucktyp der Dokumentenklassen oder {@link DruckTyp#duplex Duplex}.
107:          */
108:         public DruckTyp getDruckTyp() {
109:                 return this.dokumentenklassen.stream()
110:                                 .map(dokumentenklasse -> dokumentenklasse.getVariable(DruckTyp.class))
111:                                 .flatMap(evtlDruckTyp -> evtlDruckTyp.map(Stream::of).orElseGet(Stream::empty))
112:                                 .max(Comparator.comparing(Enum::ordinal))
113:                                 //TODO Art: Work in Progress; das orElse macht mich unglücklich ~ was könnte man hier besser tun?
114:                                 .orElse(DruckTyp.duplex);
115:         }
116:         
117:         /**
118:          * Liefert den größten FarbDrucktyp (nach Reihenfolge der definition) der {@link DokumentenklassenVariable}n der in diesem Produktionsauftrag enthaltenen {@link
119:          * Dokumentenklasse}n. Ist kein FarbDrucktyp vorhanden, so wird ein {@link FarbDruckTyp#Farbdruck FarbDruck} geliefert.
120:          *
121:          * @return größter Drucktyp der Dokumentenklassen oder {@link FarbDruckTyp#Farbdruck FarbDruck}.
122:          */
123:         public FarbDruckTyp getFarbDruckTyp() {
124:                 return this.dokumentenklassen.stream()
125:                                 .map(dokumentenklasse -> dokumentenklasse.getVariable(FarbDruckTyp.class))
126:                                 .flatMap(evtlFarbDruckTyp -> evtlFarbDruckTyp.map(Stream::of).orElseGet(Stream::empty))
127:                                 .max(Comparator.comparing(Enum::ordinal))
128:                                 //TODO Art: Work in Progress; das orElse macht mich unglücklich ~ was könnte man hier besser tun?
129:                                 .orElse(FarbDruckTyp.Farbdruck);
130:         }
131:         
132:         //
133:         // @Override
134:         // public List<Variable> getVariablen() {
135:         // final List<Variable> variables = new ArrayList<>();
136:         // this.dokumentenklassen.forEach((final Dokumentenklasse k) -> variables.addAll(k.getVariablen()));
137:         // return variables;
138:         // }
139:         //
140:         
141:         /**
142:          * Gibt eine Liste von Materialien mit Messungen wieder, welche bei der Bearbeitung des Produktionsauftrags benögtigt werden.
143:          *
144:          * @return Liste von benötigten Materialien
145:          */
146:         public List<MaterialMitMessung<?>> getBenoetigteMaterialien() {
147:                 // TODO Art: Work in Progress; Methode muss implementiert werden. Oder ein entsprechendes Feld muss angelegt werden.
148:                 return Collections.emptyList();
149:         }
150:         
151:         /**
152:          * @return das {@link ProzessModell} des {@link ProduktionsAuftrag}s
153:          */
154:         public ProzessModell getProzessModell() {
155:                 final Set<MaschinenFaehigkeit> faehigkeiten = this.dokumentenklassen.stream().map(Dokumentenklasse::getProzessModell)
156:                                 .map(ProzessModell::getFaehigkeiten).flatMap(Set::stream).collect(Collectors.toSet());
157:                 return new ProzessModell(faehigkeiten);
158:                 // TODO Art: Work in Progress; Prozessmodell gleich Prozesstyp? Klären!
159:                 // TODO Art: Work in Progress; Zusammengesetzte Prozesse sind nicht immutable
160:                 // TODO Art: Work in Progress; Wenn das Zusammenverarbeiten von Dokumentenklassen mit kompatiblen aber unterschiedlichen
161:                 // Prozessmodellen erlaubt wird, muss
162:                 // hier ggf. anders implementiert werden.
163:         }
164:         
165:         @Override
166:         public String toString() {
167:                 return "ProduktionsAuftrag{" + this.dokumentenklassen + "}";
168:         }
169:         
170:         /**
171:          * Liest aus dem {@link ProduktionsAuftrag} alle {@link DokumentenklassenVariable}n heraus, welche für die Bearbeitung des Produktionsauftrags relevant sind.
172:          *
173:          * @return eine Map von {@link MaschinenFaehigkeit} nach {@link ClassObjectMap<DokumentenklassenVariable>}.
174: * An dieser Map wird erkenntlich, für welche MaschinenFaehigkeit des Produktionsauftrags welche Eigenschaften gelten.
175:          */
176:         public Map<MaschinenFaehigkeit, ClassObjectMap<DokumentenklassenVariable>> getMaschinenRelevanteFaehigkeiten() {
177:                 // Annahme alle Dokumentenklassen eines Produktionsauftrags haben das gleiche Prozessmodell
178:                 final ProzessModell prozessmodell =
179:                                 this.dokumentenklassen.stream().map(Dokumentenklasse::getProzessModell).findFirst().orElseThrow(
180:                                                 () -> new NoSuchElementException("Die Dokumentenklassen müssen ein ProzessModell haben!"));
181:                 
182:                 final ClassObjectMap<DokumentenklassenVariable> classObjectMap4Drucken = new ClassObjectMap<>();
183:                 final ClassObjectMap<DokumentenklassenVariable> classObjectMap4Kuvertieren = new ClassObjectMap<>();
184:                 
185:                 final Map<MaschinenFaehigkeit, ClassObjectMap<DokumentenklassenVariable>> ret = new HashMap<>();
186:                 
187:                 // Das Prozessmodell enthält eine Menge von Fähigkeiten. Dies muss SimplesDrucken oder SimplesKuvertieren sein.
188:                 // Je nachdem, ob SimplesDrucken oder SimplesKuvertieren werden verschiedene Dokumentenklassenvariablen in die
189:                 // ClassObjectMap getan.
190:                 prozessmodell.getFaehigkeiten().forEach(e -> e.accept(new FaehigkeitVisitor<Void>() {
191:                         @Override
192:                         public Void handle(final Drucken drucken) {
193:                                 return null; // an der Dokumentenklasse sollte kein "komplexes Drucken" enthalten sein!
194:                         }
195:                         @Override
196:                         public Void handle(final Kuvertieren kuvertieren) {
197:                                 return null; // an der Dokumentenklasse sollte kein "komplexes Kuvertieren" enthalten sein!
198:                         }
199:                         @Override
200:                         public Void handle(final SimplesDrucken simplesDrucken) {
201:                                 final DruckTyp druckTyp =
202:                                                 ProduktionsAuftrag.this.dokumentenklassen.stream().map(dk -> dk.getVariable(DruckTyp.class))
203:                                                 .flatMap(e -> e.map(Stream::of).orElseGet(Stream::empty)).max(Comparator.naturalOrder()).orElseThrow(
204:                                                                 () -> new NoSuchElementException("Die Dokumentenklassen müssen einen Drucktypen haben!"));
205:                                 final FarbDruckTyp farbDruckTyp =
206:                                                 ProduktionsAuftrag.this.dokumentenklassen.stream().map(dk -> dk.getVariable(FarbDruckTyp.class))
207:                                                 .flatMap(e -> e.map(Stream::of).orElseGet(Stream::empty)).max(Comparator.naturalOrder()).orElseThrow(
208:                                                                 () -> new NoSuchElementException("Die Dokumentenklassen müssen einen FarbDrucktypen haben!"));
209:                                 classObjectMap4Drucken.putAll(druckTyp, farbDruckTyp, new ProzessModell(simplesDrucken));
210:                                 ret.put(simplesDrucken, classObjectMap4Drucken);
211:                                 return null;
212:                         }
213:                         @Override
214:                         public Void handle(final SimplesKuvertieren simplesKuvertieren) {
215:                                 final KuvertFormat kuvertFormat =
216:                                                 ProduktionsAuftrag.this.dokumentenklassen.stream().map(dk -> dk.getVariable(KuvertFormat.class))
217:                                                 .flatMap(e -> e.map(Stream::of).orElseGet(Stream::empty)).max(Comparator.naturalOrder()).orElseThrow(
218:                                                                 () -> new NoSuchElementException("Die Dokumentenklassen müssen einen Kuvertformat haben!"));
219:                                 
220:                                 classObjectMap4Kuvertieren.putAll(kuvertFormat, new ProzessModell(simplesKuvertieren));
221:                                 ret.put(simplesKuvertieren, classObjectMap4Kuvertieren);
222:                                 return null;
223:                         }
224:                 }));
225:                 
226:                 // TODO Art: Work in Progress; es wird nun ein neues Prozessmodell für jede MaschinenFaehigkeit erstellt
227:                 // - das funktioniert bestimm, hier aber die erinnerung, dass evtl. deswegen was schiefgeht (:
228:                 // classObjectMap4Drucken.put(prozessmodell);
229:                 // TODO Art: Work in Progress; abstimmung zwischen maschinenfähigkeit und dokumentenklassenvariablen überdenken
230:                 return ret;
231:         }
232:         
233:         /**
234:          * @return liefert den Eingangszeitpunkt der Dokumentenklasse in dem Produktionsauftrag, welche den frühsten Eingangszeitpunkt hat.
235:          */
236:         public LocalDateTime getFruehstenEingangszeitpunkt() {
237:                 return this.dokumentenklassen.stream()
238:                                 .map(Dokumentenklasse::getEingangsZeitpunkt)
239:                                 .min(LocalDateTime::compareTo)
240:                                 .orElseThrow(() -> new RuntimeException("es kann keinen Produktionsauftrag ohne Dokumentenklassen geben!"));
241:         }
242:         
243:         /**
244:          * @return Die Map der Maschinen-Belegungseinträge, wann dieser Produktionsauftrag bearbeitet wird.
245:          */
246:         public Map<Maschine, MaschinenBelegungEintrag> getMaschinenBelegungen() {
247:                 return this.maschinenBelegungen;
248:         }
249:         
250:         /**
251:          * @return Die Map der Mitarbeiter Belegungseinträge, wann dieser Produktionsauftrag bearbeitet wird. Der Key ist ein {@link Pair}, da ein
252:          * {@link Mitarbeiter} mehrfach für einen {@link ProduktionsAuftrag} belegt werden kann (Drucken und Kuvertieren)
253:          */
254:         public Map<Pair<Mitarbeiter, MaschinenFaehigkeit>, MenschBelegungEintrag> getMenschBelegungen() {
255:                 return this.menschBelegungen;
256:         }
257:         
258:         /**
259:          * @param mitarbeiter
260:          *                 Mitarbeiter, zu dem der {@link MenschBelegungEintrag} gehört.
261:          * @param maschinenFaehigkeit
262:          *                 MaschinenFaehigkeit, welche der Mitarbeiter zu diesem Belegungseintrag ausführt.
263:          * @param eintrag
264:          *                 hinzuzufügender {@link MaschinenBelegungEintrag}, zu welchem der Produktionsauftrag zu welcher Zeit bearbeitet wird.
265:          */
266:         public void addMenschBelegungsEintrag(final Mitarbeiter mitarbeiter, final MaschinenFaehigkeit maschinenFaehigkeit, final MenschBelegungEintrag eintrag) {
267:                 this.menschBelegungen.put(Pair.create(mitarbeiter, maschinenFaehigkeit), eintrag);
268:         }
269:         
270:         /**
271:          * @param maschine
272:          *                 Maschine, zu dem der {@link MaschinenBelegungEintrag} gehört
273:          * @param eintrag
274:          *                 hinzuzufügender {@link MaschinenBelegungEintrag}, zu welchem der Produktionsauftrag zu welcher Zeit bearbeitet wird.
275:          */
276:         public void addMaschinenBelegungsEintrag(final Maschine maschine, final MaschinenBelegungEintrag eintrag) {
277:                 this.maschinenBelegungen.put(maschine, eintrag);
278:         }
279:         
280:         /**
281:          * Entfernt alle Maschinen- und Mensch-Belegungseinträge am Produktionsauftrag.
282:          */
283:         public void clearBelegungsEintraege() {
284:                 this.maschinenBelegungen.clear();
285:                 this.menschBelegungen.clear();
286:         }
287:         
288:         /**
289:          * @return liefert die Beilagenarten der {@link Dokumentenklasse Dokumentenklassen} im Produktionsauftrag in aufaggregierter Form.
290:          */
291:         public BeilagenArten getBeilagenArten() {
292:                 return this.dokumentenklassen
293:                                 .stream()
294:                                 .map(dokumentenklasse -> dokumentenklasse
295:                                                 .getVariable(BeilagenArten.class)
296:                                                 .orElse(BeilagenArten.EMPTY))
297:                                 .reduce(BeilagenArten.createEmpty(), (b1, b2) -> b1.addBeilagenarten(b2.getBeilagenarten()));
298:         }
299:         
300:         /**
301:          * @return liefert die Frist des Produktionsauftrags auf Basis der frühsten Frist aller Dokumentenklassen, die im Produktionsauftrag enthalten sind.
302:          */
303:         public LocalDateTime getFrist() {
304:                 return this.getDokumentenklassen().stream().map(Dokumentenklasse::getFrist).min(Comparator.naturalOrder()).orElse(LocalDateTime.MAX);
305:         }
306:
307:         @Override
308:         public boolean equals(final Object o) {
309:                 if (this == o) {
310:                         return true;
311:                 }
312:                 if (!(o instanceof ProduktionsAuftrag)) {
313:                         return false;
314:                 }
315:
316:                 final ProduktionsAuftrag that = (ProduktionsAuftrag) o;
317:
318:                 return this.dokumentenklassen.equals(that.dokumentenklassen);
319:         }
320:
321:         @Override
322:         public int hashCode() {
323:                 return this.dokumentenklassen.hashCode();
324:         }
325: }