internal ITransportplanungJob StarteTransportplanungAsync(int saNr) { // TODO check ob TP schon in Ausführung? Contract.Requires(saNr > 0); TransportplanungJob job = new TransportplanungJob(saNr); Task planungsTask = planungsQueue.QueueTask(() => { job.Status = TransportplanungJobStatusTyp.Gestartet; try { transactionService.ExecuteTransactional( () => { LöscheTransportpläne(saNr); }); transactionService.ExecuteTransactional( () => { Sendungsanfrage sa = this.auftragServices.FindSendungsanfrageEntity(saNr); Contract.Assume(sa != null); ErzeugeTransportpläneZuSendungsanfrage(sa, job); this.auftragServices.UpdateSendungsanfrageStatus(saNr, SendungsanfrageStatusTyp.Geplant); }); job.Status = (job.Meldungen.Count == 0) ? TransportplanungJobStatusTyp.BeendetOk : TransportplanungJobStatusTyp.BeendetNok; } catch (Exception) { job.Status = TransportplanungJobStatusTyp.BeendetNok; throw; } }); job.Task = planungsTask; return job; }
/// <summary> /// Erzeugt Frachteinheiten (TEU, FEU) für Sendungspositionen. /// </summary> /// <pre>sps.Count > 0</pre> private List<Frachteinheit> ErzeugeFrachteinheitenFür(IList<Sendungsposition> sps, TransportplanungJob job) { Contract.Requires(sps.Count > 0); List<Frachteinheit> lfe = new List<Frachteinheit>(); // TODO: besserer Algorithmus nötig; Volumen der Fracht wird hier nicht beachtet, sondern nur das Gewicht. decimal restKapazität = 0m; Frachteinheit fe = null; foreach (Sendungsposition sp in sps) { if (sp.Bruttogewicht > FEU.MAXZULADUNG_TONS) { // Ware zu schwer; kann nicht transportiert werden. job.Meldungen.Add(new TransportplanungMeldung( TransportplanungMeldungTag.FrachteinheitenBildungNichtMöglich, "Das Bruttogewicht der Sendungsposition " + sp.SendungspositionsNr + " ist zu hoch.")); return new List<Frachteinheit>(); } // Falls noch Restkapazität vorhanden und nicht die erste zu erstellende Frachteinheit if (restKapazität - sp.Bruttogewicht < 0 && fe != null) { lfe.Add(fe); fe = null; } if (fe == null) { // Neue Frachteinheit anlegen, Typ (TEU, FEU) ist abhängig von Gewicht der Sendungsposition if (sp.Bruttogewicht > TEU.MAXZULADUNG_TONS) { fe = new Frachteinheit(FrachteinheitTyp.FEU); restKapazität = FEU.MAXZULADUNG_TONS; } else { fe = new Frachteinheit(FrachteinheitTyp.TEU); restKapazität = TEU.MAXZULADUNG_TONS; } } fe.Sendungspositionen.Add(sp.SendungspositionsNr); restKapazität = restKapazität - sp.Bruttogewicht; } // evtl. letzte erstellte Frachteinheit noch hinzunehmen if (fe.Sendungspositionen.Count > 0) { lfe.Add(fe); } Contract.Ensures(lfe.Count > 0); return lfe; }
private void ErzeugeTransportpläneZuSendungsanfrage(Sendungsanfrage sa, TransportplanungJob job) { Contract.Requires(sa != null); List<Frachteinheit> fe = null; fe = ErzeugeFrachteinheitenFür(sa.Sendungspositionen, job); if (job.Abort) { return; } List<List<Transportbeziehung>> p = transportnetzServices.GeneriereAllePfadeVonBis(sa.StartLokation, sa.ZielLokation); if (p.Count == 0) { job.Meldungen.Add(new TransportplanungMeldung( TransportplanungMeldungTag.KeinWegVorhanden, "Kein Weg von " + sa.StartLokation + " bis " + sa.ZielLokation + " vorhanden.")); job.Abort = true; return; } List<Transportplan> ltp = new List<Transportplan>(); foreach (List<Transportbeziehung> pfad in p) { List<TransportplanSchritt> tps = ErzeugePlanFür(pfad, fe, sa.AbholzeitfensterStart, sa.AbholzeitfensterEnde); if (tps != null) { Transportplan tp = new Transportplan(); tp.TransportplanSchritte = tps; tp.Frachteinheiten = fe.Select(_fe => (Frachteinheit)_fe.Clone()).ToList(); tp.SaNr = sa.SaNr; tp.UpdateStatus(TransportplanStatusTyp.Geplant); ltp.Add(tp); } } Contract.Ensures(ltp != null); // Füge die erzeugten Transportpläne dem Repository hinzu ltp.ForEach((tp) => { this.tp_REPO.Save(tp); }); }