Skip to content

Method: lambda$mapToEndezeitpunktProDokumentenklassen$3(MenschBelegungEintrag)

1: package simulation;
2:
3: import auftraege.Dokumentenklasse;
4: import auftraege.ProduktionsAuftrag;
5: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.ProzessModell;
6: import maschine.faehigkeit.MaschinenFaehigkeit;
7: import material.Material;
8: import material.MaterialMitMessung;
9: import mensch.Mitarbeiter;
10: import rollenbelegung.ErmittelteBelegungen;
11: import simulation.SimulationsHelper.AuslastungsHelper;
12: import simulation.SimulationsHelper.BelegungsHelper;
13: import simulation.SimulationsHelper.UeberbuchungsHelper;
14: import simulation.exceptions.PruefungsException;
15: import simulation.exceptions.SimulationsException;
16: import tec.uom.se.ComparableQuantity;
17: import util.Pair;
18: import zeit.eintraege.BelegungsEintrag;
19: import zeit.eintraege.MaschinenBelegungEintrag;
20: import zeit.eintraege.MenschBelegungEintrag;
21:
22: import javax.measure.Quantity;
23: import javax.measure.quantity.Time;
24: import java.time.LocalDateTime;
25: import java.time.temporal.ChronoUnit;
26: import java.util.ArrayList;
27: import java.util.Collection;
28: import java.util.HashMap;
29: import java.util.List;
30: import java.util.Map;
31: import java.util.Set;
32: import java.util.function.BinaryOperator;
33: import java.util.function.Function;
34: import java.util.stream.Collector;
35: import java.util.stream.Collectors;
36: import java.util.stream.Stream;
37:
38: /**
39: * Implementierung der Schnittstelle {@link SimulationsService}.
40: */
41: public class SimulationsServiceImpl implements SimulationsService {
42:         
43:         private final UeberbuchungsHelper uerbuchungsHelper;
44:         private final AuslastungsHelper auslastungsHelper;
45:         private final BelegungsHelper belegungsHelper;
46:         
47:         /**
48:          * Erstellt den Simulationsservice mit der übergebenen Zeitberechnungseinheit.
49:          * @param berechnungsZeitEinheit Zeiteinheit welcher zur Berechnung der Auslastung genutzt werden soll.
50:          */
51:         public SimulationsServiceImpl(final ChronoUnit berechnungsZeitEinheit) {
52:                 this.auslastungsHelper = AuslastungsHelper.create(berechnungsZeitEinheit);
53:                 this.uerbuchungsHelper = UeberbuchungsHelper.create();
54:                 this.belegungsHelper = BelegungsHelper.create();
55:         }
56:         
57:         /**
58:          * Erstellt den Simulationsservice mit den Standardzeitberechnungseinheiten.
59:          * {@link simulation.SimulationsHelper.SimulationsKonstanten}}
60:          */
61:         public SimulationsServiceImpl() {
62:                 this.auslastungsHelper = AuslastungsHelper.create();
63:                 this.uerbuchungsHelper = UeberbuchungsHelper.create();
64:                 this.belegungsHelper = BelegungsHelper.create();
65:         }
66:         
67:         @Override
68:         public PruefErgebnis pruefeProduktionsplanung(final Collection<MaterialMitMessung<?>> verfuegbaresMaterial,
69:                         final ErmittelteBelegungen ermittelteBelegungen) {
70:                 final PruefErgebnisBuilder pruefErgebnisBuilder = PruefErgebnis.builder();
71:                 
72:                 pruefErgebnisBuilder.gepruefeBelegungen(ermittelteBelegungen)
73:                 .ueberbuchteMitarbeiter(this.uerbuchungsHelper.ermittleUeberbuchteMitarbeiter(ermittelteBelegungen))
74:                 .ueberbuchteMaschinen(this.uerbuchungsHelper.ermittleUeberbuchteMaschinen(ermittelteBelegungen))
75:                 .produktionsAuftraegeMitFehlendenBelegungen(
76:                                 this.ermittleProduktionsAuftraegeMitFehlendenBelegungenFuerDasProzessmodell(ermittelteBelegungen))
77:                 .verbrauchtesMaterial(this.ermittleVerbrauchtesMaterial(this.ermittleBearbeiteteProduktionsauftraege(ermittelteBelegungen)))
78:                 .verfuegbaresMaterial(verfuegbaresMaterial);
79:                 
80:                 final Pair<Collection<MaschinenBelegungEintrag>, Collection<MenschBelegungEintrag>> fehlendeBelegungen =
81:                                 this.belegungsHelper.ermittleFehlendeBelegungen(ermittelteBelegungen);
82:                 
83:                 pruefErgebnisBuilder.maschinenbelegungenOhneMitarbeiterbelegung(fehlendeBelegungen.getFirst())
84:                 .mitarbeiterbelegungenOhneMaschinenbelegung(fehlendeBelegungen.getSecond())
85:                 .fehlendeFaehigkeitenFuerBelegungenProMitarbeiter(this.ermittleFehlendeFaehigkeitenProMitarbeiter(ermittelteBelegungen));
86:                 
87:                 return pruefErgebnisBuilder.build();
88:         }
89:         
90:         @Override
91:         public SimulationsErgebnis simuliereProduktionsplanung(final PruefErgebnis pruefErgebnis) {
92:                 if (!pruefErgebnis.pruefungWarFehlerfrei()) {
93:                         throw new PruefungsException(pruefErgebnis);
94:                 }
95:                 final ErmittelteBelegungen ermittelteBelegungen = pruefErgebnis.getGepruefteBelegungen();
96:                 
97:                 final SimulationsErgebnisBuilder simulationsErgebnisBuilder = SimulationsErgebnis.builder().pruefErgebnis(pruefErgebnis);
98:                 
99:                 simulationsErgebnisBuilder.verbrauchteZeitProProduktionsAuftrag(this.simuliereZeit(ermittelteBelegungen))
100:                 .auslastungProMitarbeiter(this.auslastungsHelper.simuliereAuslastungProMitarbeiter(ermittelteBelegungen))
101:                 .auslastungProMaschine(this.auslastungsHelper.simuliereAuslastungProMaschine(ermittelteBelegungen))
102:                 .nichtEingehalteneSlas(this.simuliereEinhaltungDerSlas(ermittelteBelegungen));
103:                 
104:                 return simulationsErgebnisBuilder.build();
105:         }
106:         
107:         @Override
108:         public SimulationsErgebnis pruefeUndSimuliereProduktionsplanung(final Collection<MaterialMitMessung<?>> verfuegbaresMaterial,
109:                         final ErmittelteBelegungen ermittelteBelegungen) {
110:                 return this.simuliereProduktionsplanung(this.pruefeProduktionsplanung(verfuegbaresMaterial, ermittelteBelegungen));
111:         }
112:         
113:         private Collection<Dokumentenklasse> simuliereEinhaltungDerSlas(final ErmittelteBelegungen ermittelteBelegungen) {
114:                 final Collection<Dokumentenklasse> dokumentenklassenSLANichtEingehalten = ermittelteBelegungen.getMitarbeiterbelegungen()
115:                                 .values()
116:                                 .stream()
117:                                 .flatMap(mitarbeiterBelegung -> mitarbeiterBelegung.getBelegung().stream())
118:                                 .flatMap(this.mapToEndezeitpunktProDokumentenklassen())
119:                                 .filter(this::wirdSlaNichtEingehalten)
120:                                 .map(Pair::getSecond)
121:                                 .collect(Collectors.toSet());
122:                 
123:                 // Die SLA's aller nicht zugeordneten Produktionsaufträge werden nicht eingehalten.
124:                 dokumentenklassenSLANichtEingehalten.addAll(ermittelteBelegungen.getNichtZugeordneteProduktionsauftraege().stream()
125:                                 .flatMap(produktionsAuftrag -> produktionsAuftrag.getDokumentenklassen().stream())
126:                                 .collect(Collectors.toSet()));
127:                 
128:                 return dokumentenklassenSLANichtEingehalten;
129:         }
130:         
131:         private Function<MenschBelegungEintrag, Stream<? extends Pair<LocalDateTime, Dokumentenklasse>>> mapToEndezeitpunktProDokumentenklassen() {
132:                 return menschBelegungEintrag -> menschBelegungEintrag.getZuVerarbeitenderAuftrag().getDokumentenklassen()
133:                                 .stream()
134:                                 .map(dokumentenklasse -> Pair.create(menschBelegungEintrag.getBis(), dokumentenklasse));
135:         }
136:         
137:         /**
138:          *
139:          * @return true,
140:          * wenn die SLA-Frist der Dokumentenklasse
141:          * hinter dem Fertigstellungsdatum der Bearbeitung der Dokumentenklasse liegt.
142:          */
143:         private boolean wirdSlaNichtEingehalten(final Pair<LocalDateTime, Dokumentenklasse> fertigstellungenDerDokumentenklassen) {
144:                 final LocalDateTime slaFrist = fertigstellungenDerDokumentenklassen.getSecond().getSla().getFrist(fertigstellungenDerDokumentenklassen.getSecond());
145:                 return fertigstellungenDerDokumentenklassen.getFirst().isAfter(slaFrist);
146:         }
147:         
148:         private Collection<MaterialMitMessung<?>> ermittleVerbrauchtesMaterial(final Set<ProduktionsAuftrag> produktionsauftraege) {
149:                 final Map<Material, Quantity> verbrauchtesMaterial = produktionsauftraege.stream()
150:                                 .map(ProduktionsAuftrag::getBenoetigteMaterialien)
151:                                 .flatMap(Collection::stream)
152:                                 // Gruppieren nach Material und addieren aller dazugehörigen Messungen
153:                                 .collect(SimulationsServiceImpl.
154:                                                 groupByAndMapAndReduceValue(MaterialMitMessung::getMaterial, MaterialMitMessung::getMessung, Quantity::add));
155:                 
156:                 final List<MaterialMitMessung<?>> result = new ArrayList<>();
157:                 for (final Map.Entry<Material, Quantity> messungProMaterial : verbrauchtesMaterial.entrySet()) {
158:                         result.add(MaterialMitMessung.create(messungProMaterial.getKey(), messungProMaterial.getValue()));
159:                 }
160:                 return result;
161:         }
162:         
163:         private Set<ProduktionsAuftrag> ermittleBearbeiteteProduktionsauftraege(final ErmittelteBelegungen ermittelteBelegungen) {
164:                 return ermittelteBelegungen.getMaschinenbelegungen().values().stream()
165:                                 .flatMap(maschinenBelegung -> maschinenBelegung.getBelegung().stream())
166:                                 .map(BelegungsEintrag::getZuVerarbeitenderAuftrag)
167:                                 .collect(Collectors.toSet());
168:         }
169:         
170:         private static <A, B, C> Collector<A, ?, Map<B, C>> groupByAndMapAndReduceValue(
171:                         final Function<A, B> groupingBy, final Function<A, C> mapping, final BinaryOperator<C> reducing) {
172:                 
173:                 return Collectors.groupingBy(groupingBy,
174:                                 Collectors.collectingAndThen(
175:                                                 Collectors.mapping(mapping, Collectors.reducing(reducing)),
176:                                                 optional -> optional.orElseThrow(() -> new SimulationsException("Should not happen. Optional bei groupReduce nicht present."))
177:                                                 ));
178:         }
179:         
180:         private Map<ProduktionsAuftrag, ComparableQuantity<Time>> simuliereZeit(final ErmittelteBelegungen ermittelteBelegungen) {
181:                 return ermittelteBelegungen.getMaschinenbelegungen()
182:                                 .values()
183:                                 .stream()
184:                                 .flatMap(belegung -> belegung.getBelegung()
185:                                                 .stream())
186:                                 .collect(SimulationsServiceImpl.
187:                                                 groupByAndMapAndReduceValue(BelegungsEintrag::getZuVerarbeitenderAuftrag, BelegungsEintrag::getDauer, ComparableQuantity::add));
188:         }
189:         
190:         
191:         private Map<Mitarbeiter, Collection<MenschBelegungEintrag>> ermittleFehlendeFaehigkeitenProMitarbeiter(
192:                         final ErmittelteBelegungen ermittelteBelegungen) {
193:                 final Map<Mitarbeiter, Collection<MenschBelegungEintrag>> result = new HashMap<>();
194:                 for (final Mitarbeiter mitarbeiter : ermittelteBelegungen.getMitarbeiterbelegungen().keySet()) {
195:                         final Set<MenschBelegungEintrag> belegungen = ermittelteBelegungen.getMitarbeiterbelegungen().get(mitarbeiter).getBelegung().stream()
196:                                         .filter(
197:                                                         menschBelegungEintrag -> !mitarbeiter
198:                                                         .kannMaschineBedienen(menschBelegungEintrag.getMaschineDieBedientWird()))
199:                                         .collect(Collectors.toSet());
200:                         if (!belegungen.isEmpty()) {
201:                                 result.put(mitarbeiter, belegungen);
202:                         }
203:                 }
204:                 return result;
205:         }
206:         
207:         // Ab hier Prozessmodell. Nicht korrekt. Hier fehlen noch Informationen.
208:         
209:         private Collection<ProduktionsAuftrag> ermittleProduktionsAuftraegeMitFehlendenBelegungenFuerDasProzessmodell(
210:                         final ErmittelteBelegungen ermittelteBelegungen) {
211:                 final Map<ProduktionsAuftrag, List<MenschBelegungEintrag>> belegungenProProduktionsauftrag = ermittelteBelegungen.getMitarbeiterbelegungen()
212:                                 .values()
213:                                 .stream()
214:                                 .flatMap(mitarbeiterBelegung -> mitarbeiterBelegung.getBelegung()
215:                                                 .stream())
216:                                 .collect(Collectors.groupingBy(BelegungsEintrag::getZuVerarbeitenderAuftrag));
217:                 
218:                 return belegungenProProduktionsauftrag.entrySet().stream()
219:                                 .filter(produktionsAuftrag -> !this.pruefeBelegungenPassenZuProzessmodell(produktionsAuftrag))
220:                                 .map(Map.Entry::getKey)
221:                                 .collect(Collectors.toSet());
222:         }
223:         
224:         private boolean pruefeBelegungenPassenZuProzessmodell(final Map.Entry<ProduktionsAuftrag,
225:                         List<MenschBelegungEintrag>> produktionsAuftragListEntry) {
226:                 
227:                 return this.hatPassendeBelegung(produktionsAuftragListEntry.getKey().getProzessModell(), new ArrayList<>(produktionsAuftragListEntry.getValue()));
228:         }
229:         
230:         private boolean hatPassendeBelegung(final ProzessModell prozessModell, final Collection<MenschBelegungEintrag> alleBelegungen) {
231:                 final Set<MaschinenFaehigkeit> vorhandeneFaehigkeiten = alleBelegungen.stream()
232:                                 .map(belegung -> belegung.getMaschineDieBedientWird().getMaschinentyp().getMaschinenFaehigkeit())
233:                                 .collect(Collectors.toSet());
234:                 // prüfen, ob alle Fähigkeiten des Prozessmodells von Maschinen erfüllt werden
235:                 if (prozessModell.getFaehigkeiten().isEmpty()) {
236:                         return true;
237:                 } else {
238:                         return prozessModell.getFaehigkeiten().stream()
239: .allMatch(geforderteFaehigkeit ->
240: vorhandeneFaehigkeiten.stream()
241: .anyMatch(vorhandeneFaehigkeit -> vorhandeneFaehigkeit.erfuellt(geforderteFaehigkeit)));
242:                 }
243:         }
244: }